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.


Reply via email to