rfc:function_autoloading
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:function_autoloading [2013/08/30 12:19] – add performance section ircmaxell | rfc:function_autoloading [2015/09/03 04:51] – Add streams ircmaxell | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== PHP RFC: Function Autoloading ====== | ====== PHP RFC: Function Autoloading ====== | ||
- | * Version: 0.2 | + | * Version: 0.3 |
- | * Date: 2013-08-29 | + | * Date: 2015-09-04 |
* Author: Anthony Ferrara < | * Author: Anthony Ferrara < | ||
* Status: Draft | * Status: Draft | ||
Line 11: | Line 11: | ||
PHP presently offers the ability to import class-like structures (classes, interfaces and traits) via a callback (or series of them) that can be registered. This lets a developer " | PHP presently offers the ability to import class-like structures (classes, interfaces and traits) via a callback (or series of them) that can be registered. This lets a developer " | ||
- | Presently, other types of symbols tables are not autoloadable. This RFC proposes a new unified autoloading mechanism to unify autoloading efforts across all three symbol tables (class, function and constant). | + | Presently, other types of symbols tables are not autoloadable. This RFC proposes a new unified autoloading mechanism to unify autoloading efforts across all three symbol tables (class, function, stream wrapper |
===== Proposal ===== | ===== Proposal ===== | ||
Line 21: | Line 21: | ||
This proposal registers the following constants: | This proposal registers the following constants: | ||
- | * //php\AUTOLOAD_ALL | + | |
- | | + | * //php\AUTOLOAD_FUNCTION |
- | | + | * //php\AUTOLOAD_CONSTANT |
- | | + | * //php\AUTOLOAD_STREAM |
- | ==== Functions ==== | + | ==== Userland |
- | This proposal registers the following functions: | + | This proposal registers |
- | === bool php\autoload_register(callable $callback, int $type = php\AUTOLOAD_ALL, bool $prepend = false) === | + | === bool php\autoload_register(callable $callback, int $type, bool $prepend = false) === |
- | This function behaves similar to the current // | + | This function behaves similar to the current // |
- | === bool php\autoload_unregister(callable $callback) === | + | === bool php\autoload_unregister(callable $callback, int $type = 0) === |
- | This function behaves similar to the current // | + | This function behaves similar to the current // |
- | ==== Behavior ==== | + | === array php\autoload_list(int $type) |
- | Registering autoloaders with the new API will allow callbacks to be fired on class, | + | This function |
- | === Default Behavior | + | === function_exists() |
- | The default behavior | + | A new optional boolean argument |
- | <file php basic_usage.php> | + | === defined() === |
- | <?php | + | |
- | php\autoload_register(function($name, | + | |
- | var_dump($name, | + | |
- | switch ($type) { | + | |
- | case php\AUTOLOAD_FUNCTION: | + | |
- | eval(" | + | |
- | break; | + | |
- | case php\AUTOLOAD_CLASS: | + | |
- | eval(" | + | |
- | break; | + | |
- | case php\AUTOLOAD_CONSTANT: | + | |
- | define($name, | + | |
- | break; | + | |
- | } | + | |
- | }); | + | |
- | foo(); // string(3) " | + | |
- | new foo(); // string(3) " | + | |
- | foo; // string(3) " | + | |
- | ?> | + | |
- | </ | + | |
- | === Single Type Behavior === | + | A new optional boolean argument is added to // |
- | 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). | + | ==== Internal Typedefs ==== |
- | <file php single_type.php> | + | This proposal adds the following internal structures: |
- | <?php | + | |
- | php\autoload_register(function($name, | + | |
- | var_dump($name, | + | |
- | eval(" | + | |
- | // We don't need a switch, since we only register for functions. | + | |
- | }, php\AUTOLOAD_FUNCTION); | + | |
- | foo(); // string(3) " | + | |
- | new foo(); // FATAL_ERROR | + | |
- | ?> | + | |
- | </ | + | |
- | === Multiple Type Behavior | + | === zend_autoload_func |
- | By passing a bitwise combination of constants to the register | + | This structure stores |
- | <file php multiple_type.php> | + | <code c> |
- | <?php | + | typedef struct zend_autoload_func |
- | php\autoload_register(function($name, | + | |
- | | + | |
- | | + | zval *callable; |
- | case php\AUTOLOAD_FUNCTION: | + | } _zend_autoload_func; |
- | eval(" | + | </code> |
- | break; | + | |
- | case php\AUTOLOAD_CONSTANT: | + | |
- | define($name, | + | |
- | break; | + | |
- | | + | |
- | }, php\AUTOLOAD_FUNCTION | php\AUTOLOAD_CONSTANT); | + | |
- | foo(); // string(3) " | + | |
- | foo; // string(3) " | + | |
- | new foo(); // FATAL_ERROR | + | |
- | ?> | + | |
- | </file> | + | |
- | === Registering The Same Callback Multiple Times === | + | ==== Internal Functions ==== |
- | Only the first registration of a callback will succeed: | + | This proposal adds the following ZEND_API functions/ |
- | <file php single_registration.php> | + | === void* zend_autoload_call(zend_string *name, zend_string *lname, int type) === |
- | <?php | + | |
- | $callback | + | |
- | var_dump($name, $type); | + | |
- | switch ($type) { | + | |
- | case php\AUTOLOAD_FUNCTION: | + | |
- | eval(" | + | |
- | break; | + | |
- | case php\AUTOLOAD_CLASS: | + | |
- | eval(" | + | |
- | break; | + | |
- | case php\AUTOLOAD_CONSTANT: | + | |
- | define($name, | + | |
- | break; | + | |
- | } | + | |
- | }; | + | |
- | php\autoload_register($callback, | + | |
- | php\autoload_register($callback, | + | |
- | foo(); // string(3) " | + | |
- | foo; // FATAL_ERROR | + | |
- | ?> | + | |
- | </ | + | |
- | ==== Performance ==== | + | This function will call an autoloader of the specified type. It requires two versions of the name, one which is the called case, and one which is the normalized lookup case. In the case of case-sensitive constants, they should be identical. In the case of insensitive constants, functions and classes, //lname// should be a lowercase version of the name. |
- | The following benchmarks are all run on a non-debug build compiled with // | + | === int zend_autoload_register(zend_autoload_func* func, int type, int flags) === |
- | === Class Loading === | + | This will register an autoload function with the specified flags (prepend is currently the only supported flag). |
- | 1000 classes were generated, each in a single file. The following test script was used to execute the following tests: | + | === int zend_autoload_unregister(zend_autoload_func* func, int type) === |
- | <file php benchmark_autoloading.php> | + | This will unregister an autoloader |
- | <?php | + | |
- | spl_autoload_register(function($class) { | + | |
- | require __DIR__ . '/ | + | |
- | }); | + | |
- | $start | + | === int zend_lookup_function(const char *name, int name_length, |
- | for ($i = 0; $i < 1000; $i++) { | + | |
- | $class | + | Lookup a function by name, using autoloading |
- | new $class; | + | |
- | } | + | |
- | $end = microtime(true); | + | |
- | echo " | + | === int zend_lookup_function_ex(const char *name, int name_length, |
- | ?> | + | |
- | </file> | + | |
- | * Master' | + | Lookup a function by name, optionally calling the autoloader. |
- | * Proposed // | + | |
- | Therefore, there is no performance regression when autoloading classes | + | === ZEND_LOOKUP_FUNCTION_BY_NAME(name, fbc) === |
- | === Functions === | + | This macro will find a function in the symbol table, or attempt to autoload it if not defined. The name must be a zend_string. |
- | 1000 functions were generated and placed in a single file. The following test script was used to test if there was any change to function call time for a defined function: | + | === ZEND_LOOKUP_FUNCTION_BY_KEY(name, |
- | <file php benchmark_functions.php> | + | This macro will find a function in the symbol table, or attempt to autoload it if not defined. This separates the called function in //name// from the looked up function in //key//. Both name and key must be zend_string. |
- | <?php | + | |
- | require_once ' | + | |
- | $start | + | === ZEND_LOOKUP_FUNCTION_BY_NS_KEY(name, key, fbc) === |
- | for ($i = 0; $i < 1000; $i++) { | + | |
- | $func = ' | + | |
- | $func(); | + | |
- | } | + | |
- | $end = microtime(true); | + | |
- | echo " | + | This macro will find a function |
+ | |||
+ | ==== Behavior ==== | ||
+ | |||
+ | Registering autoloaders with the new API will allow callbacks to be fired on class, function and/or constant missing errors. | ||
+ | |||
+ | === Single Type Behavior === | ||
+ | |||
+ | 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). | ||
+ | |||
+ | <file php single_type.php> | ||
+ | <?php | ||
+ | php\autoload_register(function($name, | ||
+ | var_dump($name, | ||
+ | eval("function $name(){}" | ||
+ | // We don't need a switch, since we only register for functions. | ||
+ | }, php\AUTOLOAD_FUNCTION); | ||
+ | foo(); // string(3) | ||
+ | new foo(); // FATAL_ERROR as no autoloader is registered | ||
?> | ?> | ||
</ | </ | ||
- | * Master: average 0.000216 Seconds to call 1000 functions | + | === Registering The Same Callback Multiple Times For Different Types === |
- | * Proposal: average 0.000218 Seconds to call 1000 functions | + | |
- | Therefore, there is no performance regression to normal | + | <file php multiple_registration.php> |
+ | <?php | ||
+ | $callback = function($name) { | ||
+ | var_dump($name); | ||
+ | if ($name === ' | ||
+ | eval(" | ||
+ | } else { | ||
+ | define($name, | ||
+ | } | ||
+ | }; | ||
+ | php\autoload_register($callback, | ||
+ | php\autoload_register($callback, | ||
+ | foo(); // string(3) " | ||
+ | FOO; // string(3) " | ||
+ | ?> | ||
+ | </ | ||
==== Userland Backwards Compatibility ==== | ==== Userland Backwards Compatibility ==== | ||
Line 233: | Line 186: | ||
This implementation greatly simplifies the (internal) handling of autoloading in general. | This implementation greatly simplifies the (internal) handling of autoloading in general. | ||
- | ==== Why support multiple " | + | ==== Why not support multiple " |
- | It is more of a "why not" question. Supporting multiple types of autoloaded constructs in a single | + | Existing autoloaders may support |
+ | |||
+ | ==== What Filename Conventions Does This Support? ==== | ||
+ | |||
+ | None, and all. This proposal presently implements no type of file loading handler. | ||
+ | |||
+ | The only thing that is implemented is the ability to register | ||
+ | |||
+ | ==== Doesn' | ||
+ | |||
+ | Nope! The reason is that the current autoloading mechanism | ||
+ | |||
+ | For example, the implementation hinges on a global variable which sets the php-level callback to call on autoload. This requires setting up a // | ||
+ | |||
+ | The implementation of // | ||
+ | |||
+ | This refactor cleans both of these pieces up significantly. | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 265: | Line 234: | ||
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
- | PHP 5.6.x | + | PHP 7.1.x |
===== SAPIs Impacted ===== | ===== SAPIs Impacted ===== | ||
Line 274: | Line 243: | ||
See Backward Incompatible Changes | See Backward Incompatible Changes | ||
- | |||
- | ===== New Constants ===== | ||
- | |||
- | * // | ||
- | * // | ||
- | * // | ||
- | * // | ||
===== php.ini Defaults ===== | ===== php.ini Defaults ===== | ||
Line 324: | Line 286: | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
- | There is a proof-of-concept | + | A patch will be created shortly |
- | + | ||
- | This patch is not production ready, but serves as a demonstration of the functionality. | + | |
===== References ===== | ===== References ===== | ||
Line 344: | Line 304: | ||
* 2013-08-29 0.1 Initial Creation | * 2013-08-29 0.1 Initial Creation | ||
* 2013-08-30 0.2 Add performance section and basic benchmarks | * 2013-08-30 0.2 Add performance section and basic benchmarks | ||
+ | * 2015-09-04 0.3 Re-proposed |
rfc/function_autoloading.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1