On Tue, Jun 16, 2026 at 10:29 AM Alex Rock <[email protected]> wrote:

> Le 16/06/2026 à 06:45, Michael Morris a écrit :
>
>
> On Mon, Jun 15, 2026 at 5:45 AM Alex Rock <[email protected]> wrote:
>
>> Namespaces being just a globally accessible and define-able symbols
>> system is exactly why, so far, a PHP package cannot define "private
>> internal" code. The way the language works already allows
>> autoload-hijacking in order to override code from external libs, or even
>> hack the visibility (like removing "final" or "private" keywords before
>> autoloading the file...).
>>
>
> PHP has never kept people from shooting themselves in the foot. And in the
> past it's came with some big guns too (Register Globals in PHP 3 anyone?).
> Enforcing namespace visibility will come at a cost in performance, and it
> won't be enough to stop people from shooting themselves because PHP code is
> quite mutable. I don't see much of a point in trying to guide people's
> coding, especially in a language that doesn't have a set paradigm.  That
> is, in Java, you're using classes. In PHP you can approach things that way,
> but you write purely procedurally. You can use the language as it was
> originally conceived - a templating language.
>
> I think it's morally good to bring new features to the core that disallow
> someone from shooting themselves in the foot. Readonly classes, property
> hooks, etc., are methods for maintainers to be able to stricten their code
> so that end users don't shoot themselves in the foot. Yet we have the
> Reflection API that permits a huge lot of things, and combining with
> autoload hacking or bounded closures, it means that all these requirements,
> strictening tools, etc., are *contracts* we sign with maintainers. If
> someone uses any hacky tool built in PHP to override its native behavior,
> it's at their own risk. But the language allows it.
>
> With my suggestion for modules, having all structures being declared
> globally but with a prefix still allows someone to hack into it. It just
> lowers the pressure on how it's developed in the core, in order for it to
> be both simple to use, but also simpler to implement. Doesn't prevent feet
> shots, but has a big warning sign nonetheless.
>
>
>
> When you say modules, what are talking about, because multiple languages
> implement "modules" in different ways. JavaScript is the most well known,
> but Go also has modules and they are quite different and support versioning
> out of the box. In each of these examples there is a requirement that the
> programmer write code to import the modules at some place either in the
> project (Go) or in every bloody file in the project (JavaScript). PHP
> doesn't require this, instead autoloading symbol definitions as they are
> encountered.
>
> There are different terms available for the things we talk about, so as a
> reminder to the two/three people reading this message:
>
>    - Module = file, similar to JS. This implies that everything defined
>    in the file is private, unless "publicly exposed", either via a "public"
>    keyword (as Larry suggests in his modules-brainstorming document), or an
>    "export" statement (similar to JS/TS).
>    - Module = package, in that case, this means that a module is composed
>    of several files, but a module/package needs an entrypoint to define its
>    components. Larry's aforementioned idea is about using an INI file as
>    entrypoint that prevents double-loading of a list of files, but this could
>    be implemented with other methods: my proposal for "module = file" could
>    add a "package" system without a need for an INI file, and based purely on
>    the list of publicly available structures from the main imported file, but
>    implies a bidirectional relationship between the "main package file" (aka
>    "entrypoint") and the "package-included-only file". It's just a different
>    approach.
>
> None of these approaches removes namespaces, and considering my first idea
> and re-thinking it after all the comments in here, I think focusing on
> "using namespaces for that" is definitely the best approach. My proposal
> still stands, it just needs an update to better use namespaces for that
> need.
>
>
> NPM (not Node, node is the engine not the package/dependency manager) does
> this using aliases. PHP doesn't have a way to alias symbols at compile
> time. It would be nice if it did - I've suggested it as a parameter to
> include not knowing at the time of the suggestion that include isn't a
> function, it's a statement, so `include "file.php"` is the same as
> `include("file.php")`. Setting that aside, PHP projects rarely execute the
> include themselves - they let an autoloader handle it, so the autoloader
> must know which version to load. This isn't something that even NPM does -
> it just aliases and makes both libraries available. The caller still must
> specify which library is being pulled in.
>
> Node modules have a single point of entry, defined in the package.json
> file but usually index.js. In most Node packages this index.js imports all
> the public parts of the package and immediately exports them. Further, an
> import in node is an object (as is everything in JavaScript) that
> corresponds to that file.  Hence
>
> import { foo, bar } from 'MyPackage';
>
> This is using JavaScripts dereference mechanic to pluck members of an
> object into the current symbol table.  I could go on, but I think it's more
> on topic to just say that Node's import/export mechanic, elegant as it
> looks, is highly bound to JavaScript's scope rules and  how its symbol
> table works.  These aren't compatible with PHP.
>
> I'm a bit familiar with Node.js's import model. PHP could be partly
> compatible with this in the future, but complete scoped encapsulation of a
> single PHP file is too much of a paradigm change for PHP itself. My
> proposal is making this "private" by prepending a null character and hash
> to all "included modules" whatever their kind, so that it *feels* private,
> but still behaves similarly to how PHP currently works.
> Less maintenance for the core team, zero BC break (purely additive and
> opt-in), can be transparent for the end-user (and *is* transparent for
> transient dependencies), still overridable and hackable by developers. Some
> of the reasons why PHP became famous in the first place.
>
>
>
> For one, PHP has two symbol tables - one for variables (which is why all
> variables start with $ ) and one for everything else. Variables are
> affected by function scope, nothing else is. For example, if you define a
> function within a function in JavaScript that function will be private to
> the function it is defined in - it can't be seen in other scopes. In PHP
> the function will be visible on the symbol table.
>
> For another, Node gives each file its own module scope. To move a symbol
> from one file to another you should use export and import. This creates a
> clear chain of custody for objects and symbols, but by God it also creates
> a LOT of boilerplate that the PHP community has no interest in replicating.
>
> Without the chain of custody you rapidly run into trouble. It doesn't
> matter if you try to allow the user to put a prefix on the namespace as I
> once suggested, or have PHP's engine prefix it automagically somehow - you
> still need to correctly disambiguate every blasted reference to that
> namespace. This is no easy task - take a look at the code of Strauss -
> https://github.com/BrianHenryIE/strauss That project allows you to
> rewrite a package with a new namespace, in effect doing it in userland. But
> as a precaution it prefixes every single package imported and severs the
> tie back to the original packagist.  Strauss is used by several WordPress
> plugins to make composer library use possible while still remaining
> portable between WordPress sites.
>
> Interesting, and auto-prefixing namespaces for module=packages systems is
> IMO the easiest way to implement this without breaking the compiler nor the
> engine. It keeps everything as-is, and visually provides all that's needed
> for a "modules/packages" system to work: encapsulated private structures,
> an explicit public API, and the ability to load the same structures in the
> same namespaces because they are internally hidden with a hash, similarly
> to anonymous classes.
>
>
>
>
>> The only drawback of having modules like that would be that final
>> dependency trees in Composer would be non-flat, but again, I think this
>> non-flat system should be opt-in. Similarly to how flat systems are
>> opt-in in the Node.js ecosystem (and trust me, I've tried to enforce
>> "flat" dependencies resolutions in certain Node projects, and it's a
>> huge hassle). Luckily, the PHP ecosystem is quite fine so far, compared
>> to Node, and I would definitely keep the "flat" system in Composer for
>> as long as possible, and make non-flat resolutions only case-specific
>> (which is rare, and usually framework-dependent, like with Wordpress
>> plugins for instance).
>>
>
> I don't think it's a reasonable ask of Composer or any other dependency
> manager to try to resolve this without having a clear binding map like the
> one JavaScript forces you to create by how its module system works.
>
> Composer doesn't have to change, because modules might be autoloadable.
> Whatever the solution found: if it's a bidirectional relationship (meaning
> any included file contains information on the "package" it's in, guiding to
> the entrypoint) or with a config file (like with an INI file), it can be
> built-in, and Composer would be compatible as long as loaded structures are
> public and not internal to the module.
>
>
>
> This is the Container thread - I changed the subject line on my previous
> reply although I did include (was: ) so that people could track I was
> forking.
>
> I don't have much to add beyond my previous post. I haven't heard from
> anyone with engine experience about the feasibility or difficulty of what I
> propose.  To review (for anyone just joining but missing the previous
> message)
>
> 1. The user signals to the engine they want to include a php file AND
> process it independent of the current execution environment. No shared user
> defined symbols or variables.
> 2. That file returns an interface so that the calling thread can talk to
> the child.
> 3. As the processes reside on different threads these calls will need to
> be asynchronous to be optimal, otherwise the caller will be in a blocked
> state while the child executes the called method. It can work without the
> PHP Async / Await RFC's conclusion, but it won't be in ideal form without
> it.
>
> Containers provide process isolation. Say I have a WordPress plugin that I
> want to use composer libraries with. Say, Guzzle.  I can write my own
> container interface without touching Guzzle's code exposing the parts of
> Guzzle I need for my plugin. Since WordPress has no current core composer
> support I would need to carry a loader in my distro to be ran on the
> install hook of the plugin, bringing in composer and letting it in turn
> pull the libraries that I need to use.  If someone later writes a plugin
> that uses an incompatible version of Guzzle that doesn't matter - even if
> they lazily load it into the main symbol table by not using a container.
> My plugin is isolated.
>
> That isolation comes at a price. Each plugin has an independent vendor
> directory with no way to resolve complete redundancy. At least not in
> WordPress, which has no current composer implementation in core (I'm on the
> wp trac in a thread discussing it though).
>
> There are open questions though that must be answered before this
> container idea is seriously explored. Most critical, can PHP be made to
> handle an object passing from one thread to another? That is, continuing
> from the example above, can a client instance from one GuzzleContainer
> coexist on the main thread with a client instance from a different
> container and referencing different code? Or will methods be unable to
> cross the barrier? What are the implications for the Reflection API and
> using it to examine an object that originated from another process thread
> referencing symbols that don't exist on the current thread?
>
> The idea of containers is simple to state - but the implications are
> profound and might be unworkable. I simply don't know enough about the PHP
> engine to know.
>
> This seems completely out of a "modules" scope to me: threading comes with
> a huge cost (like state interoperability, thread healthchecks, memory
> usage, and many other things), and this brings a lot of complexity that is
> not needed yet IMO. If someone wants to "sandbox" PHP somehow, it's already
> possible to execute another PHP script from inside a PHP script via CLI,
> and passing arguments to it, but there's no back-and-forth communication,
> only a "request-response-like" system.
>
>
>
However complex threading is, the complexity of aliasing is going to be
higher. I've walked down this thought experiment several times in the last
4 years. Threading isn't easy, but the work is in progress by Edmond HT -
https://wiki.php.net/rfc/true_async

Containers, as I'm proposing them, rest on the foundation of this already
in progress RFC which in turn builds on ReactPHP, AMPHP, Swoole and others.

Reply via email to