It's been 9 months. Been researching, working on other projects, mulling
over
points raised the last time I brought this up. And at the moment I don't
think
PHP 8.5 is in its final weeks so this isn't a distraction for that. The
previous discussion got seriously, seriously derailed and I got lost even
though
I started it. I'm not going to ask anyone to dig into the archives, let's
just
start afresh.
THE PROBLEM
PHP has no way of dealing with userland code trying to write to the same
entry
on the symbol tables. Namespaces are a workaround of this and combined
with
autoloaders they've yielded the package environments we currently have
(usually
composer), but at the end of the day if two code blocks want different
versions
of the same package invoked at the same time there's going to be a crash.
This
is seen most visibly in WordPress plugins that use composer, as they resort
to
monkey-typing the composer packages they consume to avoid such collisions.
PROPOSAL
Modules - blocks of PHP code with independent symbol tables and autoload
queues.
Instead of using any new keywords along with the backwards compatibility
problems that creates three existing keywords will be used in a new way:
"use",
"require", and "yield"
The first file that PHP loads will always be on the "main thread". To bring
in
code as a module the use require structure is used. The simplest possible
version of this is as follows:
PHP Code
use require 'mymodule.php';
The contents of 'mymodule.php' have two requirements. First, a namespace is
required of a module. Second, yield statements are used to mark the
functions
classes and constants the module exports, and at least one such yield must
be
present. Hence the file may look something like this:
PHP Code
namespace MyModule;
yield function sum(a, b) { return a + b; }
Returning to our caller, it could make use of this function as follows.
PHP Code
use require 'mymodule.php';
echo MyModule::sum(3, 4);
So far there is nothing here that couldn't have been done with a static
class.
The important difference though is in behavior.
-
The module does not affect or see variables on the main thread -
including
the superglobals. A module can only get to them if it receives them as an
argument in some sort of setter yield function. -
The module does not affect or see constants or functions established on
the
main thread or in other modules. It can see and autoload classes from the
main
thread if the module author opts into this (discussed below).
The use case above is not typical - usually inclusions from modules are more
targeted.
PHP Code
use sum require 'mymodule.php';
echo sum(3, 4); // 7
Here the class is not created in the main thread, only the yielded function
is.
Aliases and multiple objects can be declared in the use just as is the case
now.
PHP Code
use sum, difference as subtract require 'mymodule.php';
And if desired the namespace of the module can be aliased on the fly using
the
wildcard operator
PHP Code
use * as AliasModule require 'mymodule.php';
AliasModule::sum(3,4);
Require continues to invoke autoloaders, even when used in the context of
use
require. The callback defined in spl_autoload_register will receive a
second
argument from this context, boolean true if the main thread is loading a
module,
and if a module is loading a module its namespace string will be sent. Hence
PHP Code
require('./vendor/composer/autoload.php')
use require 'mymodule';
// Callback will receive args ('mymodule', true)
class A;
// Callback will receive args ('A', false) - the false case should preserve
BC.
And in a module
PHP Code
namespace MyModule;
/*
- Mod Author can elect to use the global autoloader
- by passing the string "global" instead of a callback
*/
spl_autoload_register('global');
use require 'othermodule';
// Callback will receive args ('othermodule', 'MyModule')
class A;
// Callback will receive args ('A', 'mymodule')
Autoload callbacks are currently required to directly load the file. For
modules this will not work because the loading of a module file involves
the
setup of a new symbol table, autoload queue, and slightly different parsing
rules (again - namespace is required, not optional, and at least one top
level
yield statement must be present). So when an autoloader is asked about a
module
it must return the absolute path to the module, or false if it can't
resolve it
(handing off to the next loader in the queue). PHP will then load the
module as
if the filepath had been placed in the use require statement in the first
place.
CLOSING REMARKS
I want to take a moment to ruminate on what doors are opened by the above,
but
all that follows is NOT part of my proposal. The above gets what I feel is
needed - a way to cleanly run disparate packages in an application whose
authors
refuse to update it to embrace composer (cough - WordPress - cough). But
even
for projects that do embrace composer and its package management the above
makes
the prospect of a large API change in a major version far less frightening.
In
the current setup all the extensions have to be kept current and more or
less
on the same page. The larger the extension authoring set becomes the less
feasible this is - projects get abandoned, stagnate and if you have a site
that
needs such then finding a replacement or upgrading it personally can be a
pain.
The string that gets passed to the autoloader could be anything btw - rules
for
which versions the module might accept like 'mymodule@7.x' can work if the
package manager is written to parse out such, but the rules for such, not to
mention what the composer.json file or equivalent would need to look like is
outside the scope of this proposal.
It should be noted that Modules offer a much more black box behavior than
the
current namespaces and autoloaders can provide. The only part of a module
the
outside world can see is what it yields. If a class isn't yielded the
outside
world can't make an instance of it. This shielding of internal API's
should be
useful because no matter how big a note you make in the comments about how
a
class shouldn't be used by outside code sooner or later someone will do it
and
their code will break when you change the internal API. While it is their
fault
for doing such, it can be a concern especially if the use of such "internal"
API's becomes commonplace (Drupal has several such instances of this)
Finally, my previous writings on this have mused about possibly having
module files
possess vastly different parsing rules. I bring this up as a possibility
but I
won't dwell on it as it could easily become a thread derailing distraction.
That said, it should be possible to use the autoload callback to signal to
PHP
that a block of code should be loaded using the module parsing rules if
having
them be different in any way is desired. That or a new require_module
statement
could be used to pull in code under the module parsing rules.
As to why this might be desirable - I'm no expert on the engine but I'm
going
to guess that giving each module an independent symbol table will incur
overhead, possibly significant overhead. One way to claw back performance
is to
fix bugs that have been unfixable for backwards compatibility reasons.
There is
no existing module code, so in one fell swoop this code can step away from
those
problems. If this is done though it has to be done right as the window
closes
once projects with modules start appearing.
It's been 9 months. Been researching, working on other projects, mulling
over
points raised the last time I brought this up. And at the moment I don't
think
PHP 8.5 is in its final weeks so this isn't a distraction for that. The
previous discussion got seriously, seriously derailed and I got lost even
though
I started it. I'm not going to ask anyone to dig into the archives, let's
just
start afresh.snip
I've started reading, saw Wordpress... almost stopped right there, but
decided okay, this is too rash of me, read further....
"My disappointment is immeasurable and my day is ruined".gif
It ended exactly how my first judging brain wave thought it would go - this
whole thing is about fixing WordPress by changing the language. Plain and
simple.
No.
Arvīds Godjuks
+371 26 851 664
arvids.godjuks@gmail.com
Telegram: @psihius https://t.me/psihius
Am 04.05.25, 13:07 schrieb Arvids Godjuks arvids.godjuks@gmail.com:
It's been 9 months. Been researching, working on other projects, mulling
over
points raised the last time I brought this up. And at the moment I don't
think
PHP 8.5 is in its final weeks so this isn't a distraction for that. The
previous discussion got seriously, seriously derailed and I got lost
even though
I started it. I'm not going to ask anyone to dig into the archives,
let's just
start afresh.snip
I've started reading, saw Wordpress... almost stopped right there, but
decided okay, this is too rash of me, read further...."My disappointment is immeasurable and my day is ruined".gif
It ended exactly how my first judging brain wave thought it would go -
this whole thing is about fixing WordPress by changing the language. Plain
and simple.No.
snip
I don't like wordpress either. It sure is the reason why PHP became a
running gag in memes.But it exists. And if it goes away PHP might too.
Yes, we hate it, it's a mess. But can we ignore it?
I think it deserves a fair discussion.
There might even be a "simple" solution to it. Maybe a version number
that is auto-added to the namespace in composer?Maybe the wordpress community could fork composer and do it?
Like what are we talking about? 10-20 lines of code?Best
Jochen
Yes, we should ignore it when working on language design and trying to
improve it.
For whatever reason, they made a deliberate commercial decision not to do
anything about it, and this is not even touching on events of recent times
:)
Two - I already have to deal with JavaScript at times and all it's
ecosystem. I do not want another JavaScript in my PHP, thank you.
For me, any concept for modules, packages, etc, etc that ignores
autoloading is dead on arrival. Ideally it should be transparent to any
consuming code and be done on the defining side, erroring out when
attempting to load/access something internal to a namespaca/package/module.
I'm also not a fan of ability to mix multiple package versions in one code
base.
--
Arvīds Godjuks
+371 26 851 664
arvids.godjuks@gmail.com
Telegram: @psihius https://t.me/psihius
Hi!
On Sun, May 4, 2025 at 8:08 AM Arvids Godjuks arvids.godjuks@gmail.com
wrote:
It's been 9 months. Been researching, working on other projects, mulling
over
points raised the last time I brought this up. And at the moment I don't
think
PHP 8.5 is in its final weeks so this isn't a distraction for that. The
previous discussion got seriously, seriously derailed and I got lost even
though
I started it. I'm not going to ask anyone to dig into the archives, let's
just
start afresh.snip
I've started reading, saw Wordpress... almost stopped right there, but
decided okay, this is too rash of me, read further...."My disappointment is immeasurable and my day is ruined".gif
It ended exactly how my first judging brain wave thought it would go -
this whole thing is about fixing WordPress by changing the language. Plain
and simple.No.
I think that is a very short sighted statement about the proposal. I have
been using PHP for 15 years and I don't know, don't use nor don't care
about the Wordpress ecosystem. However, the proposal has immeasurable
merits to address many things that have been discussed several times on
this list over the years.
1- Private classes. Instead of the currently being discussed nested class
declaration with its own set of awkwardness, Modules would allow the
declaration of classes that are not globally visible. Regardless of the
state of Wordpress, at first glance this seems a superior proposal than
Nested Class.
2- Friends classes. It has been discussed a couple of times the
introduction of class friendship as a way to expose internals of a class
only to a specific subset of known / expected classes. This has some
foundation in the fact that you don't want to declare public attributes in
a global class. With modules, you could declare a class that is not
exported to the global scope and use public attributes knowing full well
that only classes within your own module will be able to touch them. Again,
major props to this proposal over Friends classes.
3- Class autoload vs Function autoload. There have been hundreds of hours
spent on discussing function autoloading. I don't quite remember why that
is such a hot topic and I also don't remember what it tries to accomplish,
but it seems adjacent enough to consider that maybe this proposal could be
a door on that realm as well.
4- Familiarity with the Typescript ecosystem. For better or worse, browsers
run on Javascript for 3 decades and not even Wasm is fully changing that.
This proposal is too familiar from Typescript's import / export system and
would help bridge the gap for frontend engineers to better understand the
flow of PHP code.
I haven't read (or don't remember) the old discussion. From a superficial
look of the proposal, it does seem rather awkward to not go full in with
import / export
keywords, even if it requires a soft reserved keyword.
I'm not sure the syntax would require a full hard keyword reservation?
Perhaps yield is good enough instead of export, but use require
does seem
rather odd. import ... require (as opposed to import ... from) would also
work better-ish. In any case, this threads in bikeshedding space. I guess
I'd rather have use .... require anyway than not have it at all, specially
since IDEs often end up writing it for us anyway.
--
Marco Deleu
On Sun, May 4, 2025 at 7:06 AM Arvids Godjuks arvids.godjuks@gmail.com
wrote:
It ended exactly how my first judging brain wave thought it would go -
this whole thing is about fixing WordPress by changing the language. Plain
and simple.
That is a lie. Go back and read again - I discuss how this will improve
Drupal, Symfony and other projects that embrace composer.
On Sun, May 4, 2025 at 7:06 AM Arvids Godjuks arvids.godjuks@gmail.com
wrote:It ended exactly how my first judging brain wave thought it would go -
this whole thing is about fixing WordPress by changing the language. Plain
and simple.That is a lie. Go back and read again - I discuss how this will improve
Drupal, Symfony and other projects that embrace composer.
As Larry has already extensively covered, it seems that about 80% of the
whole thing lives somewhere outside the emails you sent. That's just a bad
proposal, either rushed or hasn't been worked on past 1st version of a
draft. It is how it reads to me.
Accounting for that (and I read through your correspondence) - there is
nothing in the clarifications that didn't make me reconsider; if anything,
it turned me off even more.
I will repeat myself: I do not want a
typescript/javascript/python/rails/whatever export/import type going into
PHP. This is just going back to pre-autoloading times, where you needed to
require/include files. Yes, the autoloading part is better, but then we
have a whole mess of autoloader importing vs require/include at which point
this whole thing is a ball of spaghetti that makes no sense and I am
confused to a point I cannot make heads or tails of this whole thing.
--
Arvīds Godjuks
+371 26 851 664
arvids.godjuks@gmail.com
Telegram: @psihius https://t.me/psihius
It's been 9 months. Been researching, working on other projects,
mulling over
points raised the last time I brought this up. And at the moment I
don't think
PHP 8.5 is in its final weeks so this isn't a distraction for that.
The
previous discussion got seriously, seriously derailed and I got lost
even though
I started it. I'm not going to ask anyone to dig into the archives,
let's just
start afresh.
This proposal requires:
- Every module author to change their coding structure
- Every consumer of a package to change their coding structure
- Devs to abandon "it just works" autoloading and explicitly import packages.
- Abandoning 16 years of PSR-0/4 file convention in favor of "module = file", which will almost certainly result in multi-thousand-line files even for clean, well-factored code.
As I stated in the previous thread, this is a total nonstarter. Python/Javascript style module definition is simply not compatible with PHP. It may have been had we gone that way in 2005, but we didn't, and that ship has long since sailed.
Any module proposal worth considering can require only the first point above. Requiring work from a package author to module-ify their code is fine, though it shouldn't be onerous. But it needs to "just work" with the rest of the existing ecosystem. This proposal fails at that.
Arnaud and I spent some time last year exploring a different approach to modules that requires only trivial changes by package authors, and none by consumers:
https://github.com/Crell/php-rfcs/blob/master/modules/spec-brainstorm.md
https://github.com/arnaud-lb/php-src/pull/10
In our case, the main target was performance by giving the opcache optimizer a larger chunk of code to work with, plus the potential for namespace-private symbols. Arnaud was able to make it mostly work, and there was significant potential performance to be had, but it also ran into some very complex issues very quickly. (Circular dependencies, modules split across multiple directories, testing, etc.) We largely haven't gotten back to it as the implementation was very complex and it wasn't clear if the benefit would be worth it, though I'd still like to revisit it if possible.
--Larry Garfield
On Sun, May 4, 2025 at 5:19 PM Larry Garfield larry@garfieldtech.com
wrote:
It's been 9 months. Been researching, working on other projects,
mulling over
points raised the last time I brought this up. And at the moment I
don't think
PHP 8.5 is in its final weeks so this isn't a distraction for that.
The
previous discussion got seriously, seriously derailed and I got lost
even though
I started it. I'm not going to ask anyone to dig into the archives,
let's just
start afresh.This proposal requires:
- Every module author to change their coding structure
- Every consumer of a package to change their coding structure
- Devs to abandon "it just works" autoloading and explicitly import
packages.- Abandoning 16 years of PSR-0/4 file convention in favor of "module =
file", which will almost certainly result in multi-thousand-line files even
for clean, well-factored code.
You're 4 for 4 on falsehoods. Care to actually read what I wrote because I
know you're more intelligent and better than this and very disappointed.
It's been 9 months. Been researching, working on other projects,
mulling over
points raised the last time I brought this up. And at the moment I
don't think
PHP 8.5 is in its final weeks so this isn't a distraction for that.
The
previous discussion got seriously, seriously derailed and I got lost
even though
I started it. I'm not going to ask anyone to dig into the archives,
let's just
start afresh.This proposal requires:
- Every module author to change their coding structure
- Every consumer of a package to change their coding structure
- Devs to abandon "it just works" autoloading and explicitly import packages.
- Abandoning 16 years of PSR-0/4 file convention in favor of "module = file", which will almost certainly result in multi-thousand-line files even for clean, well-factored code.
You're 4 for 4 on falsehoods. Care to actually read what I wrote
because I know you're more intelligent and better than this and very
disappointed.
PHP Code -----------------------------------------------------------------------
namespace MyModule;
yield function sum(a, b) { return a + b; }
Every module author changes their code. (Which is reasonable.)
PHP Code -----------------------------------------------------------------------
use require 'mymodule.php';
echo MyModule::sum(3, 4);
Every caller changes their code, to use use require
and to use the pseudo-class syntax to call the function.
PHP Code -----------------------------------------------------------------------
use sum require 'mymodule.php';
echo sum(3, 4); // 7
Removes the pseudo-class syntax, but still has the "use sum require..." change for the consumer.
As described, the implication is that the millions of existing
use Some\Class\Here;
lines in code in the wild will... not work if the Some\Class package becomes a module? I think that's what's implied, but it's not clear. If that triggers autoloading, how does the autoloader know how to find it? It needs to know the module name, which as described is the file name of the module, not the class.
Since the module name is the file name, that means if a module has 50 internal classes, it must be in the same file. Hence, giant files.
If those reads of your post are inaccurate, then please show with examples how they are inaccurate, because that is how I understood your proposal text at face value.
--Larry Garfield
On Sun, May 4, 2025 at 5:38 PM Larry Garfield larry@garfieldtech.com
wrote:
PHP Code
namespace MyModule;
yield function sum(a, b) { return a + b; }
Every module author changes their code. (Which is reasonable.)
Actually no. PHP Modules are only needed if the package author wants the
functionality modules provide - specifically having an independent symbol
table and autoload queue. Existing packages don't have to change in any
way. If a module includes one their symbols will be written into that
module's symbol table. If two modules include the same package they each
write it onto their own respective symbol tables.
PHP Code
use require 'mymodule.php';
echo MyModule::sum(3, 4);
Every caller changes their code, to use
use require
and to use the
pseudo-class syntax to call the function.
Again, if they want module functionality. No one has to do this - the new
syntax was carefully chosen to let the existing syntax work as it always
has.
PHP Code
use sum require 'mymodule.php';
echo sum(3, 4); // 7
Removes the pseudo-class syntax, but still has the "use sum require..."
change for the consumer.As described, the implication is that the millions of existing
use Some\Class\Here;
lines in code in the wild will... not work if the Some\Class package
becomes a module?
This is left up to the autoloader. When you call that use statement from
the main thread the autoloader receives args ("Some\Class\Here", false).
When you call that use statement from a module the autoloader receives
arguments ("Some\Class\Here", "RequestingModule"). If the autoloader isn't
rewritten it will ignore the 2nd argument and serve out the same code for
both module and main thread.
HOWEVER, modules can define their own autoloaders and those will be
executed independent of the autoloader on the main thread. Furthermore, the
autoloader on the main thread will not be used unless the module opts into
using it.
I think that's what's implied, but it's not clear. If that triggers
autoloading, how does the autoloader know how to find it? It needs to know
the module name, which as described is the file name of the module, not the
class.
By convention the filename might be the module name, but that a convention
of package management, autoloading, some future PSR-X that is far, far
outside of scope here. The module's name is its namespace! For a module a
namespace isn't just a run time string replacement, it has a very real
effect. The namespace will be the 2nd argument of every autoload call made
from the module or any file required/included in its scope. Existing
packages don't need to be aware this is happening - but the module can have
a custom autoloader that always loads version 2 of a popular package even
if composer on the main thread is set to include version 3.
Since the module name is the file name, that means if a module has 50
internal classes, it must be in the same file. Hence, giant files.
I hope you can see why this isn't true now. The module entry file can
simply yield out its public assets like so.
namespace Vendor\Package;
require 'autoloader.php';
yield { A, B, C }
The above assuming that the autoloader knows where \Vendor\Package\A,
\Vendor\Package\B and \Vendor\Package\C are located at. If an autoloader
isn't used they'll have to be explicitly required before being yielded out.
If those reads of your post are inaccurate, then please show with examples
how they are inaccurate, because that is how I understood your proposal
text at face value.
Ok, let's go over them in turn
- Every module author to change their coding structure.
No. Modules aren't replacing the current mechanism - just augmenting it
when needed. The new syntax is only necessary when an independent symbol
table is desired. Further, there's nothing stopping a package from having
a standard require entry file that doesn't set up the symbol table and
related protections, and one that does.
- Every consumer of a package to change their coding structure
That depends on the package maintainer. They can certainly rewrite the
package such that consuming code must use module syntax to access it, but
this isn't required of them. And as mentioned above they can get clever and
provide multiple entry points to their code if they desire just as
JavaScript package devs have been doing to make sure their packages work
whether the consumer uses ESM import or CommonJS import.
- Devs to abandon "it just works" autoloading and explicitly import
packages.
I don't know where you got that from - maybe the old thread from 9 months
ago? The proposal I made last night not only takes autoloading into
account but also discusses how autoload functions will receive a second
argument moving forward that lets them make decisions about what code to
supply to modules based on whatever logic they have which is well beyond
the scope of this proposal.
I will admit that while use doesn't really do anything and is handled at
compile time, use - require evals at run time. The specified symbols come
out of the module. The module can be located with an autoloader if desired,
but it's not the same mechanism because module creation involves the
creation of a new symbol table that will be used by the module file and
EVERY file it requires and every file THEY require. This is why the
autoloader is to return a string when handling module requests for classes
because PHP should have the responsibility of attaching the code to the
correct symbol table. The autoloader is told what module is about to
receive the code. If the autoloader requires it's going to affect the
symbol table it was declared in, which is ok if the module's own autoloader
is handling the request - but if the global autoloader on the main thread
does a require it's going to affect the symbol table of the main thread.
- Abandoning 16 years of PSR-0/4 file convention in favor of "module =
file", which will almost certainly result in multi-thousand-line files even
for clean, well-factored code.
Again, I don't see this, at all. And I'm a little insulted you'd think that
I'm dumb enough to propose something that outrageous. Modules simply have
their own symbol table scope. They can import any package as they exist
today without any modification into that scope. They can therefore pull a
different version of the same package, which is desirable if they have a
compatibility issue with the latest version of the package. Those
autoloader are important, but out of scope.
Another way to look at this is in JavaScript the ESM module convention was
introduced without any package management ability and worked with raw
absolute file paths. It would be a decade before import-maps were
introduced and true integration with npm started and it's still not
finished. I'm starting from the same place, use (some symbols) require
<path> and if PHP can't find the path it queries the autoloader and gives
it a chance to return a path for PHP to use here.
All existing code stays as is, and can even evolve as is when they don't
need to worry with version mismatches. This syntax only really becomes
useful when you want to "black box" the package from the rest of the
application and allow the module to do what it needs without fear of
affecting the rest of the application. Over time it might eclipse the old
approach, but
PHP Code -----------------------------------------------------------------------
namespace MyModule;
yield function sum(a, b) { return a + b; }
Every module author changes their code. (Which is reasonable.)
Actually no. PHP Modules are only needed if the package author wants
the functionality modules provide - specifically having an independent
symbol table and autoload queue. Existing packages don't have to change
in any way. If a module includes one their symbols will be written
into that module's symbol table. If two modules include the same
package they each write it onto their own respective symbol tables.
I thought it self-evident that I was referring to "every package author that wants to expose their package as a module", not literally every owner of a package on Packagist. (Though presumably over time those two circles will increasingly overlap.) But let me make that explicit.
And, as noted, requiring the author of a package to introduce new syntax in order to turn the package into a module is a reasonable expectation. I have no issue with that.
PHP Code -----------------------------------------------------------------------
use require 'mymodule.php';
echo MyModule::sum(3, 4);
Every caller changes their code, to use
use require
and to use the pseudo-class syntax to call the function.Again, if they want module functionality. No one has to do this - the
new syntax was carefully chosen to let the existing syntax work as it
always has.
If my library is structured as a module, with yield and stuff, then how exactly would someone use it without using the use require
syntax at least?
PHP Code -----------------------------------------------------------------------
use sum require 'mymodule.php';
echo sum(3, 4); // 7
Removes the pseudo-class syntax, but still has the "use sum require..." change for the consumer.
As described, the implication is that the millions of existing
use Some\Class\Here;
lines in code in the wild will... not work if the Some\Class package becomes a module?
This is left up to the autoloader. When you call that use statement
from the main thread the autoloader receives args ("Some\Class\Here",
false). When you call that use statement from a module the autoloader
receives arguments ("Some\Class\Here", "RequestingModule"). If the
autoloader isn't rewritten it will ignore the 2nd argument and serve
out the same code for both module and main thread.
I believe you are grossly misusing the term "thread" here. There is no separate execution thread involved, just scoped symbol tables.
See note further down about the rest of the points raised here.
HOWEVER, modules can define their own autoloaders and those will be
executed independent of the autoloader on the main thread. Furthermore,
the autoloader on the main thread will not be used unless the module
opts into using it.
Nothing in your initial post discussed any of this, or even implied it.
I think that's what's implied, but it's not clear. If that triggers autoloading, how does the autoloader know how to find it? It needs to know the module name, which as described is the file name of the module, not the class.
By convention the filename might be the module name, but that a
convention of package management, autoloading, some future PSR-X that
is far, far outside of scope here. The module's name is its namespace!
For a module a namespace isn't just a run time string replacement, it
has a very real effect. The namespace will be the 2nd argument of every
autoload call made from the module or any file required/included in its
scope. Existing packages don't need to be aware this is happening -
but the module can have a custom autoloader that always loads version 2
of a popular package even if composer on the main thread is set to
include version 3.
From the proposal:
use require 'mymodule.php';
echo MyModule::sum(3, 4);
How exactly does MyModule get defined? That is not at all clear.
Since the module name is the file name, that means if a module has 50 internal classes, it must be in the same file. Hence, giant files.
I hope you can see why this isn't true now. The module entry file can
simply yield out its public assets like so.namespace Vendor\Package;
require 'autoloader.php';
yield { A, B, C }
... Nothing in your initial proposal suggested that in the slightest. It did not even include yield with brackets to list multiple options.
The above assuming that the autoloader knows where \Vendor\Package\A,
\Vendor\Package\B and \Vendor\Package\C are located at. If an
autoloader isn't used they'll have to be explicitly required before
being yielded out.If those reads of your post are inaccurate, then please show with examples how they are inaccurate, because that is how I understood your proposal text at face value.
Ok, let's go over them in turn
- Every module author to change their coding structure.
No. Modules aren't replacing the current mechanism - just augmenting it
when needed. The new syntax is only necessary when an independent
symbol table is desired. Further, there's nothing stopping a package
from having a standard require entry file that doesn't set up the
symbol table and related protections, and one that does.
See above.
- Every consumer of a package to change their coding structure
That depends on the package maintainer. They can certainly rewrite the
package such that consuming code must use module syntax to access it,
but this isn't required of them. And as mentioned above they can get
clever and provide multiple entry points to their code if they desire
just as JavaScript package devs have been doing to make sure their
packages work whether the consumer uses ESM import or CommonJS import.
- Devs to abandon "it just works" autoloading and explicitly import packages.
I don't know where you got that from - maybe the old thread from 9
months ago? The proposal I made last night not only takes autoloading
into account but also discusses how autoload functions will receive a
second argument moving forward that lets them make decisions about what
code to supply to modules based on whatever logic they have which is
well beyond the scope of this proposal.
It came from the examples in the original proposal at the top of this thread:
use sum require 'mymodule.php';
echo sum(3, 4); // 7
So if I want to call sum(), I have to explicitly use sum require
it. I cannot just let the autoloader sort it out. (Assuming we were talking about a class or function autoloading ever happens, of course.)
- Abandoning 16 years of PSR-0/4 file convention in favor of "module = file", which will almost certainly result in multi-thousand-line files even for clean, well-factored code.
Again, I don't see this, at all. And I'm a little insulted you'd think
that I'm dumb enough to propose something that outrageous. Modules
simply have their own symbol table scope. They can import any package
as they exist today without any modification into that scope. They can
therefore pull a different version of the same package, which is
desirable if they have a compatibility issue with the latest version of
the package. Those autoloader are important, but out of scope.
The implication from your original post is that if I want to import 3 symbols from a module, I require a single file. That file has one or more symbols that are yield
ed. Implication: If I want 3 symbols in a module together, they have to be in the same file.
Your response here about having a fronting file that yields symbols it doesn't define, on the assumption that an autoloader will figure it out in the backend, was never stated nor implied anywhere in your proposal. Rather, it states that modules look like this:
yield function sum(a, b) { return a + b; }
IE, like Javascript or Python libraries. That is the plain reading of your original post. And naturally means that whoever is authoring that file needs to make changes to it, to at minimum add the "yield" keyword.
So before you get indignant and call me a liar ("You're 4 for 4 on falsehoods"), perhaps consider how someone you know is "more intelligent" than this can come away from your post understanding it so utterly differently than what you intended.
From your follow up statements, it seems that what you are proposing is not "modules" in any sense used in any language I am familiar with. Rather, you're proposing a symbol table hack to get around PHP's inability to load two symbols with the same name, and using module terminology to inaccurately describe it. (And thread terminology as well.) That is, it seems your intent is that I can import arbitrary code from an arbitrary package and shunt it off to a separate symbol table. But it's not clear if you intend for the package author to have to do anything to enable that. Your answers seem contradictory.
For a concrete example, I'll offer my AttributeUtils library: https://github.com/Crell/AttributeUtils/tree/master/src
It has a whole bunch of interfaces, plus a few classes. We'll focus on a subset of them for the moment.
Analyzer.php (this is the main class someone uses)
AttributeParser.php (this is an internal class used by Analyzer, you should never use it directly)
FromReflectionClass.php (an interface that other libraries implement to trigger certain functionality in Analyzer)
Say I want to modularize this library, under your proposal. What would I, as the library author, do exactly? Anything? How can I mark AttributeParser as internal-only and thou-shalt-not-use-if-you're-not-me? (That's the most common value of module systems, and the one most people in PHP seem to think of, from what I've seen.)
That library is used extensively by Serde (another of my libraries). If I modularize AttributeUtils, then what changes does Serde need to make? What would it get out of doing so?
Code examples, please.
--Larry Garfield
Resetting and moving the proposal writeup to a github hosted markdown file
here:
https://github.com/michael-lloyd-morris/php-modules-rfc/blob/main/php-modules.md
On Mon, May 5, 2025 at 12:44 AM Larry Garfield larry@garfieldtech.com
wrote:
So before you get indignant and call me a liar ("You're 4 for 4 on
falsehoods"), perhaps consider how someone you know is "more intelligent"
than this can come away from your post understanding it so utterly
differently than what you intended.
I'm sorry for doing that.
From your follow up statements, it seems that what you are proposing is
not "modules" in any sense used in any language I am familiar with.
Rather, you're proposing a symbol table hack to get around PHP's inability
to load two symbols with the same name, and using module terminology to
inaccurately describe it. (And thread terminology as well.) That is, it
seems your intent is that I can import arbitrary code from an arbitrary
package and shunt it off to a separate symbol table. But it's not clear if
you intend for the package author to have to do anything to enable that.
Your answers seem contradictory.For a concrete example, I'll offer my AttributeUtils library:
https://github.com/Crell/AttributeUtils/tree/master/srcIt has a whole bunch of interfaces, plus a few classes. We'll focus on a
subset of them for the moment.Analyzer.php (this is the main class someone uses)
AttributeParser.php (this is an internal class used by Analyzer, you
should never use it directly)
FromReflectionClass.php (an interface that other libraries implement to
trigger certain functionality in Analyzer)
In answer to your question - assuming the module file is at the root of
your src directory.
<?php
module \Crell\AnalyzerModule;
export [
\Crell\Analyzer,
\Crell\FromReflectionClass
];
?>
Say I want to modularize this library, under your proposal. What would I,
as the library author, do exactly? Anything? How can I mark
AttributeParser as internal-only and thou-shalt-not-use-if-you're-not-me?
(That's the most common value of module systems, and the one most people in
PHP seem to think of, from what I've seen.)That library is used extensively by Serde (another of my libraries). If I
modularize AttributeUtils, then what changes does Serde need to make?
On that end
<?php
require_module <path_to_Crell\AnalyzerModule>;
$analyzer = new \Crell\AnalyzerModule::Analyzer();
?>
If the autoloader gets updated to identify and properly load modules
(outside the scope of this RFC) the require_module statement can be
dropped. If a use statement is desired it looks like this
<?php
use \Crell\AnalyzerModule::Analyzer; // This is legal for modules, not for
static classes.
$analyzer = new Analyzer();
?>
What would it get out of doing so?
Nothing much - it just wouldn't be able to see as deeply into the
AttributeUtils code.
Resetting and moving the proposal writeup to a github hosted markdown
file here:
https://github.com/michael-lloyd-morris/php-modules-rfc/blob/main/php-modules.md
From your follow up statements, it seems that what you are proposing is not "modules" in any sense used in any language I am familiar with. Rather, you're proposing a symbol table hack to get around PHP's inability to load two symbols with the same name, and using module terminology to inaccurately describe it. (And thread terminology as well.) That is, it seems your intent is that I can import arbitrary code from an arbitrary package and shunt it off to a separate symbol table. But it's not clear if you intend for the package author to have to do anything to enable that. Your answers seem contradictory.
For a concrete example, I'll offer my AttributeUtils library: https://github.com/Crell/AttributeUtils/tree/master/src
It has a whole bunch of interfaces, plus a few classes. We'll focus on a subset of them for the moment.
Analyzer.php (this is the main class someone uses)
AttributeParser.php (this is an internal class used by Analyzer, you should never use it directly)
FromReflectionClass.php (an interface that other libraries implement to trigger certain functionality in Analyzer)In answer to your question - assuming the module file is at the root of
your src directory.<?php
module \Crell\AnalyzerModule;export [
\Crell\Analyzer,
\Crell\FromReflectionClass
];
?>Say I want to modularize this library, under your proposal. What would I, as the library author, do exactly? Anything? How can I mark AttributeParser as internal-only and thou-shalt-not-use-if-you're-not-me? (That's the most common value of module systems, and the one most people in PHP seem to think of, from what I've seen.)
That library is used extensively by Serde (another of my libraries). If I modularize AttributeUtils, then what changes does Serde need to make?
On that end
<?php
require_module <path_to_Crell\AnalyzerModule>;$analyzer = new \Crell\AnalyzerModule::Analyzer();
?>If the autoloader gets updated to identify and properly load modules
(outside the scope of this RFC) the require_module statement can be
dropped. If a use statement is desired it looks like this<?php
use \Crell\AnalyzerModule::Analyzer; // This is legal for modules, not
for static classes.$analyzer = new Analyzer();
?>What would it get out of doing so?
Nothing much - it just wouldn't be able to see as deeply into the
AttributeUtils code.
So it's not really giving private symbols. It's not even blocking access to anything, since it can still just be included or autoloaded. What you're proposing is really just an optional loading facade (the real kind of facade) that lets you pull random symbols into a separate symbol table, accessed via separate syntax. (Either a class-like AnalyzerModule::Analyzer, or use-require.)
Putting aside for the moment the question of whether that is a good idea or not, it is definitely not "modules" in any typical sense. I really don't think calling it "modules" is doing your proposal any favors, as it's just leading to confusion. What you're describing is a name-mangling facade, or symbol table facade, or something like that. (I don't know that there is a standard name.)
I strongly recommend you recast your terminology around that, rather than "modules." That would remove a lot of confusion and allow people to review and respond to the idea you're actually proposing, now what they think a "module" should be.
--Larry Garfield
On Wed, May 7, 2025 at 10:59 AM Larry Garfield larry@garfieldtech.com
wrote:
So it's not really giving private symbols. It's not even blocking access
to anything, since it can still just be included or autoloaded. What
you're proposing is really just an optional loading facade (the real kind
of facade) that lets you pull random symbols into a separate symbol table,
accessed via separate syntax. (Either a class-like
AnalyzerModule::Analyzer, or use-require.)Putting aside for the moment the question of whether that is a good idea
or not, it is definitely not "modules" in any typical sense. I really
don't think calling it "modules" is doing your proposal any favors, as it's
just leading to confusion. What you're describing is a name-mangling
facade, or symbol table facade, or something like that. (I don't know that
there is a standard name.)I strongly recommend you recast your terminology around that, rather than
"modules." That would remove a lot of confusion and allow people to review
and respond to the idea you're actually proposing, now what they think a
"module" should be.--Larry Garfield
No proposal that replaces or even significantly alters how require et al
works will be taken seriously, much less gain traction. As long as a
package has PHP files that require can parse then clever users can direct
require the files of a package distributed this way. The only way to stop
it is to truly make files meant to be used with this unreadable to require
- and the simplest way to do that is to assume code first and drop support
for <?php ?> in these files. I'm in favor of that since I believe the
engine can parse the files faster because it should simplify the token
parsing process quite a bit. But I don't think a majority, much less the
required supermajority would be in favor of such a change, at least not
without other compelling reasons.
Rather than fight the co-existence with require I think it would be better
to harness and work with it. This would also make the changeover easier.
As for the point of whether this counts as a module - Ask 10 programmers
what a module is and expect 12 different answers. I'm patterning this on
the module pattern used in JavaScript. I'm sorry if that doesn't meet your
definition of module. I am open to any other name - component? library?
Calling it a module until a better name can be found will have to do. But
I'm not going to insult my own proposal by calling it "name-mangling facade"
Part of the problem is PHP deals with code on a per file basis, not on a
per directory one. Speaking of facades, the PSR-4 loading recommendation of
organizing classes puts a module/package facade onto PHP, but it in no way
ever has worked that way. Modules and Packages traditionally do work on
the directory level, but how do you affix such to a language that has never
had it and prevent older mechanisms of the language, such as require, from
doing an end run.
This problem hasn't been solved for years for a reason - it's not simple.
It is an easy one to give up on, as most have. I'm just too stupid to give
up I suppose.
It's been 9 months. Been researching, working on other projects,
mulling over
points raised the last time I brought this up. And at the moment I
don't think
PHP 8.5 is in its final weeks so this isn't a distraction for that.
The
previous discussion got seriously, seriously derailed and I got lost
even though
I started it. I'm not going to ask anyone to dig into the archives,
let's just
start afresh.This proposal requires:
- Every module author to change their coding structure
- Every consumer of a package to change their coding structure
- Devs to abandon "it just works" autoloading and explicitly import packages.
- Abandoning 16 years of PSR-0/4 file convention in favor of "module = file", which will almost certainly result in multi-thousand-line files even for clean, well-factored code.
As I stated in the previous thread, this is a total nonstarter. Python/Javascript style module definition is simply not compatible with PHP. It may have been had we gone that way in 2005, but we didn't, and that ship has long since sailed.
Any module proposal worth considering can require only the first point above. Requiring work from a package author to module-ify their code is fine, though it shouldn't be onerous. But it needs to "just work" with the rest of the existing ecosystem. This proposal fails at that.
Arnaud and I spent some time last year exploring a different approach to modules that requires only trivial changes by package authors, and none by consumers:
https://github.com/Crell/php-rfcs/blob/master/modules/spec-brainstorm.md
https://github.com/arnaud-lb/php-src/pull/10In our case, the main target was performance by giving the opcache optimizer a larger chunk of code to work with, plus the potential for namespace-private symbols. Arnaud was able to make it mostly work, and there was significant potential performance to be had, but it also ran into some very complex issues very quickly. (Circular dependencies, modules split across multiple directories, testing, etc.) We largely haven't gotten back to it as the implementation was very complex and it wasn't clear if the benefit would be worth it, though I'd still like to revisit it if possible.
--Larry Garfield
Just to add my $0.02 as a userland/library developer:
I agree with Larry's points - it needs to be transparent for the consumers, and it absolutely needs to align with namespaces, without any expectation about how symbols relates to files.
I personally think initially the goal should be a more minimal approach that simply introduces the concept of a module/package/whatever-term-you-like as something that exists, with an implicit relationship to a namespace.
Future RFC's could build on that - even within the same release cycle - but initially agreeing on a basic way to define "this namespace is also a <insert chosen name for a collection of code>" provides a building block for both language/runtime internal enhancements and external tooling.
Cheers
Stephen
Hello, Michael.
Thank you very much for your work. It's very interesting.
Let me look at this idea from an architectural perspective.
Did I understand correctly from the text that:
- Modules control which entities are public and which are not?
- During import, we specify which entities we want to bind to which namespace?
- Could this solution help with separating Internal and Public classes?
In other words, the information about what is public and what is
private is part of the module.
And the information about how the module is integrated into the
project lies outside the module.
Could this task be reduced to using use as
?
For example:
use \MyClass as MyClass2;
This situation is very similar to creating aliases for namespaces,
but the difference is that the alias is created not for the code being
used, but for the code being loaded.
Technically, this is quite possible to implement:
- We specify that files at a certain path will be loaded into a
different namespace. - During loading, all namespaces are inserted into the symbol table
with the desired alias, as if a person had manually renamed all the
modules.
But there is one problem here that cannot be solved at all.
PHP
lacks an abstraction over symbols. It doesn’t have a dedicated
Class
or Namespace
type — strings are used in code for that
purpose.
And that means any code that tries to load a class using a string
constant will break.
To solve this, PHP
would need to introduce a new data type. That’s
not a problem, but it does require an RFC
.
In addition, a new PSR
for packages and autoloading would be needed.
You have a great idea, but I think it requires some groundwork in
these areas first.
P.S.
I consider WordPress the best example of what rapid programming can
look like — and where it can lead. And I don’t hate it. :)
Best Regards, Ed
PHP has no way of dealing with userland code trying to write to the
same entry
on the symbol tables. Namespaces are a workaround of this and
combined with
autoloaders they've yielded the package environments we currently have
(usually
composer), but at the end of the day if two code blocks want different
versions
of the same package invoked at the same time there's going to be a
crash. This
is seen most visibly in WordPress plugins that use composer, as they
resort to
monkey-typing the composer packages they consume to avoid such collisions.
I think there are two different problems being muddled here:
- How can two completely unrelated libraries avoid accidentally
declaring something with the same name? - How can two versions of the same library be used in different parts
of the same running program, despite overlapping names?
Namespaces are not a workaround to problem number 2, they are a solution
to problem number 1: every library chooses a prefix, and avoids
declaring symbols with prefixes used by other libraries.
Problem number 2 is what you seem to be trying to address.
In languages like EcmaScript/JavaScript/TypeScript, the solution (to
both problems) is to say that declarations don't have a canonical name.
They're values that you can pass around, and their name is whatever a
local scope says it is. This has major implications on both the language
and its ecosystem:
- contracts between libraries need to be structural, because there is no
name that all libraries agree on for an interface/protocol/whatever - package managers don't resolve the graph of dependencies to a
consistent set, they install multiple copies of the same library, for
use in different scopes - package authors are free to depend on mutually incompatible concrete
implementations, rather than agreed or de facto standards and interfaces
NPM is notorious for creating a giant directory of tiny modules, because
that's what the language design encourages.
That's not how PHP works, and it never will be. In PHP (and other
languages like Java, and C#), declarations have a single fully-qualified
name. If you want two different versions of the same library, you will
need to find a way to make their declarations use different
fully-qualified names.
Most applications do not have this problem. In fact, I would say that
most applications would actively suffer from having multiple copies of
the same library installed.
The main exception, as you have pointed out, is plugin architectures
like WordPress, where the plugin might want to "privately" use some
library without impacting the host application and other plugins. For
those, userland solutions already exist - a random search turned up this
one, which lists some alternatives:
https://github.com/BrianHenryIE/strauss?tab=readme-ov-file#alternatives
I do think PHP would benefit from some native concept of "module" for
other reasons, e.g. marking internal components, optimising across
multiple files. I do not think that ES/JS/TS is a suitable model to
look at, because it is starting from a fundamentally different concept
of what a declaration is.
I also do not think that allowing multiple versions of the same
library should be a core requirement of any native module support;
enabling userland to achieve it efficiently would be a nice to have.
--
Rowan Tommins
[IMSoP]
On Wed, May 7, 2025 at 3:24 PM Rowan Tommins [IMSoP] imsop.php@rwec.co.uk
wrote:
Problem number 2 is what you seem to be trying to address.
The main thing, yes. This solution incidentally solves class privacy issues
several unrelated and failed RFC's have addressed, including Nested Classes
which is currently not doing so well in its vote.
NPM is notorious for creating a giant directory of tiny modules, because
that's what the language design encourages.
Indeed. Definitely the bathwater to be thrown out.
That's not how PHP works, and it never will be. In PHP (and other
languages like Java, and C#), declarations have a single fully-qualified
name. If you want two different versions of the same library, you will
need to find a way to make their declarations use different
fully-qualified names.
Other libraries have the means to import into a namespace because their
namespaces aren't just a quick and dirty string replacement. I've even
proposed such a long, long time ago - allowing namespace to be the second
argument of require, only to have that shot down as "require isn't a
function." or some such.
The main exception, as you have pointed out, is plugin architectures
like WordPress, where the plugin might want to "privately" use some
library without impacting the host application and other plugins.
It's not just WordPress. Drupal and other CMS's have extensions, but their
reliance on composer means abandoned plugins that need an old library can
block updating the whole system. The larger and more popular the
application is the more likely this becomes. And like it or not WordPress
haters on the board, for as much as WordPress sucks (and I will agree, it
sucks hard) it still have a 50% - 80% market share of PHP websites
depending on who you ask. A lot of this stems from the fact that end users
just want their site to work - they don't give a rat's ass about
dependencies and the like - and needing to drop a plugin to upgrade a site
will put a bad taste in their mouth at best.
For
those, userland solutions already exist - a random search turned up this
one, which lists some alternatives:
https://github.com/BrianHenryIE/strauss?tab=readme-ov-file#alternatives
I've seen Strauss in action. It's called monkey-typing. Other languages
support this sort of monkey typing to some degree - PHP can only do it by
doing an expensive and error prone programmatic keyword search of the
source files and transforming them. The end result has to be shipped with
the module, severing its dependencies from getting security updates.
I do think PHP would benefit from some native concept of "module" for
other reasons, e.g. marking internal components, optimising across
multiple files. I do not think that ES/JS/TS is a suitable model to
look at, because it is starting from a fundamentally different concept
of what a declaration is.
So what do you suggest then? Go's model? Rusts? Gradle or Maven from
Java? Shooting down stuff is trivial, finding solutions is the real work.
On Wed, May 7, 2025 at 3:24 PM Rowan Tommins [IMSoP] imsop.php@rwec.co.uk
wrote:Other libraries have the means to import into a namespace because their
namespaces aren't just a quick and dirty string replacement. I've even
proposed such a long, long time ago - allowing namespace to be the second
argument of require, only to have that shot down as "require isn't a
function." or some such.
I've no idea what you're saying here, sorry. I never mentioned autoloading in my message, because it's largely irrelevant. What's relevant is how you identify something that's been declared (e.g. a class).
The main exception, as you have pointed out, is plugin architectures
like WordPress, where the plugin might want to "privately" use some
library without impacting the host application and other plugins.It's not just WordPress.
That is why I said "plugin architectures like WordPress". I am absolutely aware that it is an example, not something unique.
I've seen Strauss in action. It's called monkey-typing. Other languages
support this sort of monkey typing to some degree - PHP can only do it by
doing an expensive and error prone programmatic keyword search of the
source files and transforming them. The end result has to be shipped with
the module, severing its dependencies from getting security updates.
So, you don't like the first example I happened to pick in a 10-second search... More interestingly:
Firstly, can PHP do something to make the rewriting easier? I've no idea, but if so, let's talk about it.
Secondly, can the rewriting be done at install time rather than in advance? I see no reason why not; seems like something to tinker with in a Composer plugin, off-topic on this list.
I do think PHP would benefit from some native concept of "module" for
other reasons, e.g. marking internal components, optimising across
multiple files. I do not think that ES/JS/TS is a suitable model to
look at, because it is starting from a fundamentally different concept
of what a declaration is.So what do you suggest then? Go's model? Rusts? Gradle or Maven from
Java? Shooting down stuff is trivial, finding solutions is the real work.
I suggest starting with what we already have: build modules on top of namespaces, not as something new and orthogonal; and leave package management (version resolution, installation, etc) to userlan, while recognising that Composer is overwhelmingly the most popular implementation.
That probably means that rewriting namespace prefixes remains the only way to isolate "private" versions of a dependency, and I am totally fine with that.
Rowan Tommins
[IMSoP]
The main exception, as you have pointed out, is plugin architectures
like WordPress, where the plugin might want to "privately" use some
library without impacting the host application and other plugins.It's not just WordPress. Drupal and other CMS's have extensions, but
their reliance on composer means abandoned plugins that need an old
library can block updating the whole system. The larger and more
popular the application is the more likely this becomes. And like it
or not WordPress haters on the board, for as much as WordPress sucks
(and I will agree, it sucks hard) it still have a 50% - 80% market
share of PHP websites depending on who you ask. A lot of this stems
from the fact that end users just want their site to work - they don't
give a rat's ass about dependencies and the like - and needing to drop
a plugin to upgrade a site will put a bad taste in their mouth at best.
If we're going to cite WordPress as a design factor, then we should also recognize that WordPress has virtually no involvement in PHP Internals, and its version requirement history means that even if PHP 8.5 were to ship with the perfect multi-version-loading system, it would be around 10 years before WordPress even supported that PHP version. As a practical matter, it's just not a meaningful factor.
I do think PHP would benefit from some native concept of "module" for
other reasons, e.g. marking internal components, optimising across
multiple files. I do not think that ES/JS/TS is a suitable model to
look at, because it is starting from a fundamentally different concept
of what a declaration is.So what do you suggest then? Go's model? Rusts? Gradle or Maven from
Java? Shooting down stuff is trivial, finding solutions is the real
work.
Quoting from my first post in this thread:
Arnaud and I spent some time last year exploring a different approach
to modules that requires only trivial changes by package authors, and
none by consumers:https://github.com/Crell/php-rfcs/blob/master/modules/spec-brainstorm.md
https://github.com/arnaud-lb/php-src/pull/10In our case, the main target was performance by giving the opcache
optimizer a larger chunk of code to work with, plus the potential for
namespace-private symbols. Arnaud was able to make it mostly work, and
there was significant potential performance to be had, but it also ran
into some very complex issues very quickly. (Circular dependencies,
modules split across multiple directories, testing, etc.) We largely
haven't gotten back to it as the implementation was very complex and it
wasn't clear if the benefit would be worth it, though I'd still like to
revisit it if possible.
I don't believe that is a perfect proposal, but it is a different approach that Arnaud's experimentation shows has the potential for as much as a 20% performance improvement in some situations. That's nothing to sneeze at. There's still challenges with it, both implementation and DX, but let's not pretend that aping Python is the only option that exists.
I believe that qualifies as "real work."
--Larry Garfield