Le 09/06/2026 à 22:34, Rowan Tommins [IMSoP] a écrit :
On 09/06/2026 10:39, Alex Rock wrote:
Many existing libraries could migrate parts of their internal
structures (the ones not supposed to be supported by their BC policy)
to modules with no impact on userland code.
I think this is the crux for me, and why I reacted as I did to your
initial e-mail. It doesn't look anything like how PHP libraries lay
out their code today, so migrating to it would involve a complete
change of coding style.
That's the goal here: keep BC at all costs, and make modules transparent
in userland. Change of coding style is opt-in for libraries/frameworks
maintainers that want internal structures whenever they need it.
In JavaScript, it has always been common practice to ship libraries as
a single file, so the user only needed to add a single <script> tag.
Inside that file, a single function creates a private scope,
and everything declared is hidden unless passed out in some way. The
modern module format still basically works that way: "import"
references a file, and "export" defines objects to pass back.
In PHP, we've always had include/require, and for the last 20+ years,
we've had autoloading, so packages commonly have many small files.
Libraries have always prefixed names to avoid colliding with other
code, and namespaces made that easier. Loading a package usually means
configuring an autoloader to look in directory X for namespace prefix
Y, and reference the classes you need by name.
My proposals for modules do not imply that everything is shipped in one
single file. It implies that a module allows "hiding" some of its
internal structures instead of exposing everything to the global space,
so that instead of adding "@internal" or "final" to everything to avoid
users extending such code, you can just ship that internal code along
the rest.
Changing every file in a library to use import and export statements
would be a huge chore, and break all sorts of assumptions, for very
little benefit. The natural boundary in PHP is not an included file,
it's a registered namespace prefix.
As said: it's not mandatory. And namespaces can be overriden at will in
userland, while internal module code cannot (unless you succeed in
hacking the hashed prefix and sort of extend that, but modules should
make this impossible, and if not, as hard as possible).
And the future of this might help improving the ecosystem by
providing a different way to package applications themselves: if the
first loaded file is a module, and all files in the module tree are
also modules and all "include/require" are done on
compiler-resolvable paths, this means that an entire PHP app could be
bundled as the opcodes.
OpCache already handles the difference between per-file compilation
and "linking" between files; the reason not to ship opcodes is more
about the stability of the OpCode format itself, which can change in
even minor versions.
Module-level optimisation would potentially be a significant benefit,
but again the key there is how to define a boundary around *multiple*
files, to cache them as a single unit. If the cache key has to include
*extra* granularity, for "file X imported from file Y" vs "file X
imported from file Z", that just leads to more cache misses.
In my mind, the goal is to deport runtime "a list of compiled files are
executed" concept into a compile-time "when importing a module, its ast
is directly copy/pasted here, with safeguards to avoid redefining the
same structures in the symbols table". Since a module file will contain
a hashed prefix (based on file path & content), it's (almost) impossible
to have two similar hashes that would conflict with each other, and the
safeguard is only here to make sure two files can import the same module
and reuse the defined structures directly from memory if they were set
already.
A module doesn't necessary need to be a single unit: as said, you can
still have a "PSR-4-way of implementing modules", where modules are all
exporting one single PHP class, and it shouldn't make any difference in
the first place. The differences will be in the internal structures that
can be necessary for said PHP class. Sure it might break PSR-4 itself,
hence why I do *not* suggest implementing true PSR-4 on modules, because
that's not really the same thing, but their similarity allow for
internal data structures, constants, etc., that allow maintainers a bit
more freedom on their BC policy.