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:55] – jpauli | internals:extensions [2013/04/10 13:28] – jpauli | ||
---|---|---|---|
Line 123: | Line 123: | ||
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 137: | Line 137: | ||
</ | </ | ||
- | Extensions such as //standard// are mandatory, they are always compiled and built statically. This is because further dynamically loaded extensions may depend on stuff provided by standard, this happens sometimes as standard provides lots of functionnality. | + | 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** | **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 //zend_module_entry//, so they are PHP extensions. | + | The pointers are pointers to the '' |
Example: | Example: | ||
Line 163: | Line 163: | ||
</ | </ | ||
- | To register a new PHP extension, the engine calls for zend_register_module_ex(zend_module_entry *module). | + | To register a new PHP extension, the engine calls for '' |
- | zend_register_module_ex() | + | This does few things : |
* Checks for extension dependencies, | * Checks for extension dependencies, | ||
* Checks if the extension has already been registered, if it is the case, warns | * 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 zend_register_functions(module-> | + | * 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 additionnal 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 additionnal functionnality 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 combinaison 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 beeing 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 quiet 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 beeing 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 beeing in conflict with B, but B could be loaded after A, hence the check wont 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 | ||
+ | zend_extension_startup() is called on the Zend extensions registry | ||
+ | | ||
+ | '' | ||
+ | Dont be fooled here, it's not the '' | ||
+ | |||
+ | ===== 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 : '' | ||
+ | |||
+ | ===== Main schema ===== |
internals/extensions.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1