Re: [PHP-DEV] RFC Draft - Improved Autoloading

[email protected] (Alex Rock) Tue, 7 Jul 2026 22:49:40 +0200
Newsgroups php.internals
Message-ID <[email protected]>
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.
>
>
> INTRODUCTION
> Numerous 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.
>
> PROPOSAL
> Users 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 VERSIONS
> This 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 IMPACT
> This 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 😕