On Tue, May 13, 2025, 9:32 a.m. Deleu <deleu...@gmail.com> wrote: > Hi! > > It's been a few days since I wanted to send this email to internals, but > real life has been a bit chaotic so I apologize if it comes off as if I > didn't research the archives enough. I glossed over the Module conversation > from 10 months ago and the one that recently surfaced and after deeply > thinking about Rowan's and Larry's comments I wanted to throw this idea > into the pit. > > Lets preface the conversation with the fact that 1) a module system for > PHP has been discussed for several years and 2) if there was an easy and > perfect solution it would have been long implemented by now. With that in > mind, I think there are mainly two major "camps": the ones that would > support something new similar to Node ESM vs CommonJS and those who won't. > Having dealt with this mess on the NodeJS side, I'm still on the side that > would support it because even though it's been 10 years worth of "mess", it > has greatly empowered progress. But I think PHP is too conservative to > indulge this camp, so I'm going to focus on Rowan's and Larry's position of > "we need something that builds on top of namespace, not replace it". > > If we consider how GitHub, Composer and Docker Hub works, we can pin a > very important aspect of "namespaces": {entity}/{project}. Entity may > either be an individual or an organization, but the concept is mostly the > same. Although it can be argued that PHP has nothing to do with that, I > think that could be a "good-enough" foundation considering the complexity > of the subject. Here is what we could do: > > ```php > > <?php declare(strict_types=1); > > namespace Acme\ProjectOne > { > public class Foo {} // same as class Foo {} > > private class Bar {} // only visible inside Acme\ProjectOne > > protected class Baz {} // visible inside Acme > } > > namespace Acme\ProjectTwo > { > new \Acme\ProjectOne\Foo; // Work as always > > new \Acme\ProjectOne\Bar; // Fatal error: Uncaught Error: Cannot > instantiate private class \Acme\ProjectOne\Bar from \Acme\ProjectTwo > > new \Acme\ProjectOne\Baz; // Works > } > > namespace Corp\Corp > { > new \Acme\ProjectOne\Foo; // Work as always > > new \Acme\ProjectOne\Bar; // Fatal error: Uncaught Error: Cannot > instantiate private class \Acme\ProjectOne\Bar from \Corp\Corp > > new \Acme\ProjectOne\Baz; // Fatal error: Uncaught Error: Cannot > instantiate protected class \Acme\ProjectOne\Baz from \Corp\Corp > } > > > function (\Acme\ProjectOne\Foo $foo) {} // Works as always > > function (\Acme\ProjectOne\Bar $bar) {} // Open question: allow or disallow > it? > > function (\Acme\ProjectOne\Baz $baz) {} // Open question: allow or disallow > it? > > ``` > > This would allow public, private and protected classes in a way that I > believe to be useful for the large ecosystem that surrounds Composer. From > my extremely limited understanding of the engine, I think the easy/natural > step would be to allow private/protected classes to be *received* outside > its namespace because a type declaration does not trigger autoload. > However, an important question is whether this is enough groundwork that > could lead to optimizations that have been discussed when the topic of > module is brought up. For instance, if type-hint outside the module is > disallowed, could that make it easier to pack and optimize an entire module > if we could instruct PHP how to load all symbols of a namespace all at > once? I don't know. > ------------------------ > > As I'm writing this down I don't know if it could be related or if its > something only making sense inside my head, but I see the above proposal > paired with a potential amendment to PSR-4 (and Composer), to stimulate the > community to pack small related symbols in a single file with an opt-in > approach: > > composer.json: > ``` > // ... > > "autoload": { > "psr-4-with-module": { > "App\\": "app/", > } > }, > > // ... > ``` > > ``` > > <?php declare(strict_types=1); > > // app/Foo/Bar.php > namespace App\Foo; > class Bar {} > > > // app/Foo.module.php > namespace App\Foo; > enum Baz {} > enum Qux {} > > > new \App\Foo\Bar; // loads app/Foo/Bar.php > \App\Foo\Baz::option; // file app/Foo/Baz.php does not exist, tries > app/Foo.module.php before giving up > \App\Foo\Qux::option; // app/Foo.module.php has been loaded and Qux has been > registered already > > ``` > > Thoughts? > > -- > Marco Deleu >
Hey all, Anyone familiar with C++'s friend keyword? It’s not a direct replacement for modules, but it solves similar problems — allowing trusted classes or functions to access private/protected members without making them public. The idea: allow one class to explicitly grant access to another class or function. Useful for tightly coupled code that still wants to maintain encapsulation. Since friend would be a new keyword, it’s safe to add (currently a parse error). Examples: ` class Engine { private string $status = 'off'; friend class Car; friend function debugEngine; } class Car { public function start(Engine $e) { $e->status = 'on'; // allowed } } function debugEngine(Engine $e) { echo $e->status; // also allowed } ` This avoids reflection, awkward internal APIs, or overly permissive visibility. Could be useful in frameworks, testing tools, or any place where selective trust is helpful. Thoughts? Hammed >