Le 07/07/2026 à 05:06, Michael Morris a écrit :
After feedback from Rowan Tommins, Larry Garfield, pmjones and Alex Rock I'm gong to move to a first draft of a spec for this idea.INTRODUCTIONNumerous attempts have been made to create function and constant autoloaders within namespaces, and they've ran into problems concerning symbol lookup. This RFC proposes to sidestep this issue by allowing userland to register an improved autoloader able to not only handle the first time classes are sought out by the engine, but also the first time the engine sees a namespace. This allows userland code to set up a namespace - load its functions, constants and/or perform other initialization work deemed necessary by the user.PROPOSALUsers will be able to provide a callback to spl_autoload_register() that has two string arguments instead of one. If they do those arguments are as follows.``` function (string $class, string $namespace) {} ```When the engine encounters a class that it does not have on the symbol table it will invoke the callback for the class as it presently does. The namespace argument will only be populated if the engine has not seen this namespace. For example``` $a = new A\AClass(); $b = new A\BClass(); ``` Line 1: Autoloader will be called with arguments ("A\AClass", "A") Line 2: Autoloader will be called with arguments ("A\BClass", null)PHP will also call the autoloader when it encounters the namespace keyword referencing a namespace it hasn't seen before. Hence``` namespace B; ``` This will result in a call to the autoloader with arguments (null, "B") If a namespace chain is encountered only one call is made. Hence ``` namespace A\B\C; ``` Will result in a call to the autoloader of (null, "A\B\C").NOTE. The engine will mark namespaces "A" and "A\B" as seen in addition to the specified namespace "A\B\C", so the autoloader needs to work out if it should do anything for those namespaces as well.BACKWARDS INCOMPATIBLE CHANGES None foreseen.I guess technically if someone has already written an autoloader that takes 2 or more arguments the code would break because the engine previously was not sending 2 arguments. However, is this a realistic thing to worry about? I can't think of a rational reason to write such an autoloader.Note that autoloaders written to this spec should happily run on older PHP versions because those versions will always give null to the 2nd argument causing the autoloader to only act on its class code. An autoloader that prepares namespaces based on classes is still possible, but unsafe since a function from the namespace could get called.PROPOSED PHP VERSIONSThis should be safe on any minor release. Realistically this won't be available until 8.7 I would guess as we're already in 8.6 alpha. I don't think this could be coded before feature freeze, but I don't know the engine well. I think I can do this myself though if needed, especially if someone volunteers to coach me.RFC IMPACTThis RFC allows a route to function autoloading by sidestepping issues it has had. Quoting Rowan Tommins (with example updated to reflect this proposal):> This really nicely side-steps the global-vs-namespace sequence problem > that function autoloading always runs into: by the time the engine > reaches an unqualified name, the namespace loader has already run for > the current namespace, and defined any functions it wants. The engine > can fall back to the global namespace, and error immediately if that > fails, without an extra autoload call. > > To illustrate: > > namespace Acme\Foo\Widgets; > use Omnicorp\Bar\Helpers; > $name = make_widget_name(); > echo strlen($name); > Helpers\spin_wheels(); >> Line 1: All autoloaders that accept 2 arguments are called with arguments> (null, 'Acme\Foo\Widgets') > >Line 2: Use statement, has no run-time effect > > Line 3: Attempt to call Acme\Foo\Widgets\make_widget_name(); this might > have been defined by the loader at line 1. If it doesn't exist, attempt > to call \make_widget_name(); if that doesn't exist, throw an Error. > > Line 4: Attempt to call Acme\Foo\Widgets\strlen(); if that doesn't > exist, call \strlen() which is built-in, so never fails. > > Line 5: Attempt to call Omnicorp\Bar\Helpers\spin_wheels(); if it> doesn't exist, call all autoloaders that accept two arguments with arguments > (null, 'Omnicorp\Bar\Helpers') and try again. If it still doesn't exist, throw> an Error.And to extend on his example, when a class is referenced from a previously unknown namespace the autoloader will receive both arguments as outlined above and be responsible for executing both setup processes.This RFC will almost certainly trigger a related PSR standard that takes namespace setup into account. Once that is settled the maintainers of composer will likely implement such a standard. One possible route is to follow Python's lead of having a __setup__.php file in the namespace's directory if the namespaces are set up in mirror to the file system setup, but nothing in this RFC mandates that approach.
I'm not sure that I like the current shift of the first ideas you exposed.At first, it was about adding an internal hook when encountering a "namespace" statement. Something that could be used to setup libraries *after* autoload, for instance.
Here, your new draft suggests an update to the "use" statement, which currently has absolutely zero impact, and doesn't trigger autoload at all. Plus, it would trigger in two different ways, depending on whether the final symbol exists in the symbols table or not, and triggering another call with the namespace as argument.
This sounds out of scope and a bit too much direct impact, because it will happen on any unloaded symbol, especially built-in functions that have not been fully-qualified using a "use function strlen"-like statement or a fully-qualified reference, like "\strlen()".
These are two completely different proposals to me, and deserve two different RFCs:
- Namespace declaration hooks, via a hypothetical "spl_namespace_declaration_register($callback)" function (or whatever other naming that fits better - Triggering autoload and namespace declaration hooks when resolving unresolved "use" statements (at whatever steps, of the compilation or runtime)
Another thing: updating existing spl_autoload_register callbacks with a non-deterministic additional "$namespace" argument seems like a no-go to me: this goes beyond what autoload currently does. Triggering a namespace-declaration hook should be done *after* autoload IMO, to separate both features as much as possible.
I mean this especially with this example of yours:
```
$a = new A\AClass();
$b = new A\BClass();
```
Line 1: Autoloader will be called with arguments ("A\AClass", "A")
Line 2: Autoloader will be called with arguments ("A\BClass", null)
The above behavior suggestion implies that it works like this:
Since autoloader is called with ("A\AClass", "A") , the result of it
might be an exception for undefined class, or an error coming from the
namespace declaration hooks, all at the same place and coming from the
same callbacks.
If you do it in two ways so that the two features are separated inside
engine itself , autoloaders won't have to change at all, but
willing-devs that need to listen to namespace declarations will have
their own code, namespaces, stack traces, etc., if an error occurs. But
what is certain is that if the namespace hook is reached, it means the
autoloading process was a success: can't trigger namespace hook if the
autoloader throws an exception, or if the PHP file that's loaded doesn't
declare any namespace at all (which would be a violation of some PSR
rules, depending on the project, but it's another subject). This
guarantees that all namespace hooks will be called *after* a successful
autoload, therefore the potential classes in the declared namespace are
already autoloaded.
Still, it still implies a non-deterministic assumption about "what has already been declared". A namespace hook should not take care at all on whether the classes in its namespace have been declared already, or it might "ensure" it with a bunch of graceful "require_once" calls. And if these required files correspond to the same namespace, no further hooks are called. If required files belong to sub-namespaces, however, hooks will be called... and here comes the chain of calls.
PHP's autoload is powerful, but things can become really annoying, since autoload is called for ANY non-existing symbol (classes, functions, constants) that have to be resolved before being actually called. Thanks to Composer, we have classmaps (and even authoritative classmaps) that drastically improves performances, but it's not built-in PHP. Adding namespace declaration hooks in the process would kinda enforce Composer to update its behavior and its dumped autoloaders to include all namespace hooks that can be registered by libraries, and since autoload isn't predictable about the order in which classes will be loaded, it's gonna be the exact same for namespaces, if not worse.
I think the whole thing is an interesting idea, but so far, there's still quite a lot of things that can become messy depending on how it's implemented, and in consideration of the impact on the ecosystem itself, and I'm not seeing a lot of values or problems solved, apart the potential to solve the "function autoload" issue that's been there for a while, but it looks quite overkill as a feature if it only solves function autoload 😕
