internals:extensions
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
internals:extensions [2013/04/09 16:28] – jpauli | internals:extensions [2016/11/04 09:53] – Fixed typos yohgaki | ||
---|---|---|---|
Line 11: | Line 11: | ||
Both extension kinds share lots of stuff. The difference between both types is mainly in hooks they register into the Engine. | Both extension kinds share lots of stuff. The difference between both types is mainly in hooks they register into the Engine. | ||
+ | Remember that, despite it is very uncommon, an extension can be both a PHP extension and a Zend extension at the same time. Xdebug is a good example. | ||
Here are the PHP extension structures : | Here are the PHP extension structures : | ||
Line 118: | Line 119: | ||
===== Statically compiled extensions ===== | ===== Statically compiled extensions ===== | ||
- | All extensions may be built statically or dynamically. | + | Lots of extensions may be built statically or dynamically. Some require one or the other compilation mode, but they are uncommon. |
- | When built statically, the extension is loaded **earlier** than when its built dynamically | + | When built statically, the extension is loaded **earlier** than when it' |
So, the first thing to remember is that an extension may behave differently if it is loaded statically against dynamically, | So, the first thing to remember is that an extension may behave differently if it is loaded statically against dynamically, | ||
- | When you prepare your sources, part of the prepare work is to write a file //main/ | + | When you prepare your sources, part of the prepare work is to write a file '' |
This files contains an array with the pointers to all the to-be-statically-compiled extensions. Here is an example : | This files contains an array with the pointers to all the to-be-statically-compiled extensions. Here is an example : | ||
<code c> | <code c> | ||
Line 136: | Line 137: | ||
</ | </ | ||
- | Extensions such as standard are mandatory, they are always compiled and built statically. | + | Extensions such as '' |
+ | **Only PHP extensions may be built statically, Zend extensions may not. Extensions which are both PHP and Zend, may be built statically** | ||
- | The first thing PHP does when it loads, is to get those pointers out, and load those extensions | + | The first thing PHP does when it loads, is to get those pointers out, and load those extensions. |
+ | The pointers are pointers to the '' | ||
+ | |||
+ | Example: | ||
+ | <code c> | ||
+ | #define phpext_standard_ptr & | ||
+ | |||
+ | zend_module_entry basic_functions_module = { /* {{{ */ | ||
+ | STANDARD_MODULE_HEADER_EX, | ||
+ | NULL, | ||
+ | standard_deps, | ||
+ | " | ||
+ | basic_functions, | ||
+ | PHP_MINIT(basic), | ||
+ | PHP_MSHUTDOWN(basic), | ||
+ | PHP_RINIT(basic), | ||
+ | PHP_RSHUTDOWN(basic), | ||
+ | PHP_MINFO(basic), | ||
+ | PHP_VERSION, | ||
+ | STANDARD_MODULE_PROPERTIES | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | To register a new PHP extension, the engine calls for '' | ||
+ | This does few things : | ||
+ | * Checks for extension dependencies, | ||
+ | * Checks if the extension has already been registered, if it is the case, warns | ||
+ | * Registers the PHP extension functions into the global function table, calling '' | ||
+ | |||
+ | ===== Parsing the ini file to get more extensions ===== | ||
+ | |||
+ | '' | ||
+ | It then adds the names of the extensions to two different lists, one for PHP exts : extension_lists.functions, | ||
+ | You can find the code by looking for the function '' | ||
+ | |||
+ | Before PHP5.5, Zend extensions needed to be provided the full path to the extension (ini token " | ||
+ | As of 5.5, this in not the case any more and both PHP and Zend extensions are loaded providing only the file name, not the full path. | ||
+ | |||
+ | At this stage, PHP and Zend extensions have been parsed from ini files, but nothing more has been done. | ||
+ | |||
+ | ===== Registering additional extensions from the SAPI module ===== | ||
+ | Again before loading/ | ||
+ | Those get registered here, the same way statically compiled got registered just few steps before, to recall : | ||
+ | * Checks for extension dependencies, | ||
+ | * Checks if the extension has already been registered, if it is the case, warns | ||
+ | * Registers the PHP extension functions into the global function table, calling '' | ||
+ | |||
+ | For example, the Apache SAPI (apxs2), registers a PHP extension that provides functions related to Apache. Each SAPI may register one or more PHP extension providing additional functionality for itself. Apache is a good example. | ||
+ | The CLI SAPI doesn' | ||
+ | |||
+ | ===== Loading the ini parsed extensions ===== | ||
+ | |||
+ | Here comes time where PHP will effectively **load** Zend and PHP extensions, calling some hooks onto them. '' | ||
+ | First thing to know : **Zend extensions are loaded before PHP extensions** | ||
+ | |||
+ | ==== Loading Zend extensions ==== | ||
+ | '' | ||
+ | * zend_extension_entry | ||
+ | * extension_version_info | ||
+ | |||
+ | If those symbols are missing, the Zend extension will fail to load | ||
+ | |||
+ | Then API compatibility is checked from '' | ||
+ | After that, buildid is checked. Buildid is a combination of the previously checked API number, debug flag and thread safety flag (ZTS). Other components may be used for buildid check. Zend extension' | ||
+ | |||
+ | | ||
+ | |||
+ | After those checks, the Zend extensions get registered. '' | ||
+ | A message is dispatched to all previously registered Zend extension to make them know a new Zend extension is being registered. Then, '' | ||
+ | This system has been designed so that Zend extensions may know each other, and eventually fail loading if they guess they are not compatible with each other. | ||
+ | |||
+ | | ||
+ | |||
+ | Finally, the Zend extension is registered, it is then added to an exported global register storing Zend extensions pointers : '' | ||
+ | |||
+ | ==== Loading PHP extensions ==== | ||
+ | After Zend extensions got registered, comes the PHP extensions turn. '' | ||
+ | So, I repeat again : to register a new PHP extension, the engine calls for '' | ||
+ | This does few things : | ||
+ | * Checks for extension dependencies, | ||
+ | * Checks if the extension has already been registered, if it is the case, warns | ||
+ | * Registers the PHP extension functions into the global function table, calling '' | ||
+ | |||
+ | At this stage, the extensions order is not relevant. Extensions are simply registered, nothing more will happen here | ||
+ | |||
+ | PHP extensions registration is quite the same as Zend extensions registration : dlopen() the shared object, and checks for compatibility. | ||
+ | PHP extensions must export a '' | ||
+ | |||
+ | The '' | ||
+ | <code c> | ||
+ | #define ZEND_GET_MODULE(name) \ | ||
+ | BEGIN_EXTERN_C()\ | ||
+ | ZEND_DLEXPORT zend_module_entry *get_module(void) { return & | ||
+ | END_EXTERN_C() | ||
+ | |||
+ | #ifdef COMPILE_DL_FOO | ||
+ | ZEND_GET_MODULE(foo) | ||
+ | #endif | ||
+ | </ | ||
+ | |||
+ | Then, the two fields '' | ||
+ | |||
+ | After that, the loading mechanism fills in the '' | ||
+ | Now the PHP extension is going to be registered into a shared global variable, called '' | ||
+ | The registration step will perform two checks against the PHP extension being registered : | ||
+ | * If the PHP extension is already present in the registry, warning then failure at registration | ||
+ | * PHP extension dependencies **conflicts only** are checked | ||
+ | |||
+ | The system checks for the eventually attached '' | ||
+ | * A PHP extension can tell the system that it is not compatible with another already registered extension, so it will fail loading itself into the engine | ||
+ | * A PHP extension can tell the system that it requires another PHP extension to be loaded before itself | ||
+ | |||
+ | Here, **only conflicts are checked**, and as there is no particular registration order, a PHP extension A could declare being in conflict with B, but B could be loaded after A, hence the check won't work and you'll probably get some trouble. | ||
+ | When dealing with conflicts, it is better to sort the extensions in the php.ini file as a FIFO. | ||
+ | **PHP extensions will be registered in the exact same order they' | ||
+ | |||
+ | ==== Activating PHP extensions ==== | ||
+ | After registration, | ||
+ | PHP extensions are activated before Zend extensions | ||
+ | |||
+ | '' | ||
+ | Then comes the " | ||
+ | It checks the extension field '' | ||
+ | Note that conflicts requirements have already been checked against, at extension loading (see last chapter) | ||
+ | After that, the extension globals are registered (call to '' | ||
+ | |||
+ | ==== Activating Zend extensions ==== | ||
+ | Zend extensions are then activated **after** PHP extensions | ||
+ | '' | ||
+ | | ||
+ | '' | ||
+ | | ||
+ | |||
+ | ===== Extensions lifetime ===== | ||
+ | You may know PHP's lifetime. Very basically, '' | ||
+ | We already detailed php_module_startup() previously, to show how both PHP extensions and Zend extensions live into this stage. | ||
+ | |||
+ | ==== Request startup ==== | ||
+ | Zend extensions come first, and their '' | ||
+ | PHP extensions come second, and their '' | ||
+ | |||
+ | ==== Request shutdown ==== | ||
+ | PHP extensions come first, and their '' | ||
+ | Zend extensions come after, and their '' | ||
+ | A third hook is called : '' | ||
+ | |||
+ | ==== PHP shutdown ==== | ||
+ | PHP is ending, so as we are clean guys, we wrote code for PHP to clean up its environment in a right way and don't rely on the process terminating to destroy all the environment. | ||
+ | PHP extensions are first destroyed. This is done internally by relying on the Hashtable functionalities. As the '' | ||
+ | It calls '' | ||
+ | Finally, if the extension were to be loaded with '' | ||
+ | |||
+ | After PHP extensions have all been shut down and unloaded, Zend extensions will be. | ||
+ | '' | ||
+ | |||
+ | ===== Main schema ===== | ||
+ | |||
+ | {{: |
internals/extensions.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1