This RFC proposes a new unified autoloading mechanism to allow autoloading of class types (which includes classes, interfaces and traits) and functions. Currently only class type autoloading is possible in PHP.
This example shows a separate autoloader being registered for classes,
<?php function classTypeAutoloader($name, $type) { if ($type !== AUTOLOAD_CLASS) { return; } if ($name !== 'foo') { return; } // Being able to define classes inside a function // already exists in PHP and is convenient for an example class foo { public function __construct() { echo "class was created"; } } } function functionAutoloader($name, $type) { if ($type !== AUTOLOAD_FUNCTION) { return; } if ($name !== 'foo') { return; } function foo() { echo "foo was called"; } } autoload_register('classTypeAutoloader', AUTOLOAD_CLASS); autoload_register('functionAutoloader', AUTOLOAD_FUNCTION); // As is currently possible, trigger class autoload new Foo(); //output: class was created // The triggers the capability to autoload a function foo(); // output: function was autoloaded and called
This proposal registers the following constants:
The `AUTOLOAD_CLASS` is used for registering autoloaders for all the different types, which will be classes, interfaces and traits.
The `AUTOLOAD_FUNCTION` is used for registering autoloading for functions.
This proposal adds the following functions:
This function behaves similar to the current spl_autoload_unregister function, and unregisters a callback that was previously registered. Note that if you registered the same callback for multiple types, this will unregister all of them unless the $type argument is specified.
This function will return a list of all registered autoloaders for a specific type.
A new optional boolean argument is added to `function_exists()` to match the behavior of `class_exists()` when it comes to autoloading functions.
Registering autoloaders with the new API will allow callbacks to be fired on class and function missing errors.
By passing a single constant to the register function, the callback will only be called for types that match (the `$type` parameter is still set, but will never vary).
<?php autoload_register(function($name, $type) { var_dump($name, $type); eval("function $name(){}"); // We don't need a switch, since we only register for functions. }, AUTOLOAD_FUNCTION); foo(); // string(3) "foo" int(2) new foo(); // FATAL_ERROR as no autoloader is registered ?>
By passing a bitwise-or'd constant to the register function, the callback will only be called for types that match).
<?php autoload_register(function($name, $type) { var_dump($name, $type); switch ($type) { case AUTOLOAD_FUNCTION: eval("function $name(){}"); break; case AUTOLOAD_CLASS: $code = <<< CODE class $name { public function __construct() { echo "class $name was created"; } } CODE; eval($code); break; } }, AUTOLOAD_FUNCTION | AUTOLOAD_CLASS); foo(); // string(3) "foo" int(2) new foo(); ?>
This RFC proposes to strip the current spl_autoload_register functionality, and make spl_autoload_* simple proxies for registering core autoloaders. They will function exactly as they do now, but under the hood they will be using the new interface.
This means that calls to spl_autoload_functions() will include any autoloader (which indicates support for AUTOLOAD_CLASS ) registered through autoload_register(). However, all autoloaders registered via spl_autoload_register will set the pass_type flag to 0, meaning that only a single argument will be passed to the callback. This is for compatiblity.
The autoload related SPL globals have been removed, due to the implementation being centralized.
There should be no user-land BC changes.
PECL extensions which rely on the EG(autoload_func) global variable will break (due to refactor).
A quick scan of LXR shows that only the [optimizer](http://lxr.php.net/xref/PECL/optimizer/optimize.c#4660) extension would change.
PECL extensions which reply on the SPL type autoload_func_info will break (due to refactor).
A quick scan of LXR shows that no extensions use this.
PECL extensions which rely on the SPL globals will break (due to refactor).
A quick scan of LXR shows that no extensions use this.
PHP 8.0
None.
See Backward Incompatible Changes
None.
None yet.
A previous version of this RFC included support for autoloading constants and streams. These have been excluded from this RFC for the following reasons.
Although it would be possible to add constant autoloading, the position of this RFC is that being unable to directly reference functions by name is a more important problem to address.
If we added constant autoloading now, that would have a very high chance of limiting the choices surrounding being able to reference functions. Because of that, this RFC does not include constant autoloading.
Stream autoloading is excluded from this RFC to reduce the size of the RFC. It would be possible to add it in a later version.
At some point PHP may support types other than classes as parameter, return or property types. For example perhaps enums:
enum Compass { North, South, East, West } function foo(Compass $direction) { ... } foo(Compass::East);
Or typed callables:
type logger = callable(string $message): void; // Use that type function uses_logger(logger $fn) {...}
It should be possible to add to autoloading.
As PHP cannot determine what type a parameter, return or property type will be before it is loaded, the loading of those types will need to go through the same mechanism that is used for class autoloading.
At that point it would make sense to either rename `AUTOLOAD_CLASS` to be `AUTOLOAD_TYPE` or more likely, add a new constant with the same value, leaving `AUTOLOAD_CLASS` as legacy.
autoload_register('callableTypeAutoloader', AUTOLOAD_TYPE); function callableTypeAutoloader($name, $type) { if ($type !== AUTOLOAD_CLASS) { return; } if ($name !== 'logger') { return; } type logger = callable(string $message): void; }
A patch will be created before voting.
Accept the RFC yes/no.