Send a blank email to [email protected] to get a copy of this message
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