internals:extensions

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
internals:extensions [2013/04/10 15:08] jpauliinternals:extensions [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 137: Line 137:
 </code> </code>
  
-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 ''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 functionality.
 **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**
  
Line 172: Line 172:
  
 ''php_init_config()'' is called, it parses the different ini files (mainly php.ini) and looks for the tokens "extension=" and "zend_extension=". ''php_init_config()'' is called, it parses the different ini files (mainly php.ini) and looks for the tokens "extension=" and "zend_extension=".
-It then adds the names of the extensions to two different lists, one for PHP exts : extension_lists.functions, and one for Zend exts : extension_lists.engine. Both are zend_llist type.+It then adds the names of the extensions to two different lists, one for PHP exts : extension_lists.functions, and one for Zend exts : extension_lists.engine. Both are zend_llist (Linked List) type.
 You can find the code by looking for the function ''php_ini_parser_cb()'' You can find the code by looking for the function ''php_ini_parser_cb()''
  
Line 180: Line 180:
 At this stage, PHP and Zend extensions have been parsed from ini files, but nothing more has been done. 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 =====+===== Registering additional extensions from the SAPI module =====
 Again before loading/registering anything from ini files, any SAPI may call ''php_module_startup()'' passing it an array of PHP extensions to load (pointer to zend_module_entry*) Again before loading/registering anything from ini files, any SAPI may call ''php_module_startup()'' passing it an array of PHP extensions to load (pointer to zend_module_entry*)
 Those get registered here, the same way statically compiled got registered just few steps before, to recall : Those get registered here, the same way statically compiled got registered just few steps before, to recall :
Line 187: Line 187:
   * Registers the PHP extension functions into the global function table, calling ''zend_register_functions(module->functions)''   * Registers the PHP extension functions into the global function table, calling ''zend_register_functions(module->functions)''
  
-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.+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't register any extension   The CLI SAPI doesn't register any extension
      
Line 203: Line 203:
  
 Then API compatibility is checked from ''extension_version_info'' against current running PHP. Zend extension's ''api_no_check()'' may be called if mismatch. Then API compatibility is checked from ''extension_version_info'' against current running PHP. Zend extension's ''api_no_check()'' may be called if mismatch.
-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's ''build_id_check()'' function may be called as well, though it's pretty uncommon.+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's ''build_id_check()'' function may be called as well, though it's pretty uncommon.
  
-   Usually, this system just checks that the extension contains code that will be loadable and undertsnadable by the PHP internal code actually loading it. For example, an extension built with ZTS activated will hit those checks and won't be loaded on a PHP running without ZTS.+   Usually, this system just checks that the extension contains code that will be loadable and understandable by the PHP internal code actually loading it. For example, an extension built with ZTS activated will hit those checks and won't be loaded on a PHP running without ZTS.
        
 After those checks, the Zend extensions get registered. ''zend_register_extension()'' is called to do this job. After those checks, the Zend extensions get registered. ''zend_register_extension()'' is called to do this job.
-A message is dispatched to all previously registered Zend extension to make them know a new Zend extension is beeing registered. Then, ''message_handler()'' is called on all already registered Zend extensions, and is given as argument the pointer to the beeing-registered extension.+A message is dispatched to all previously registered Zend extension to make them know a new Zend extension is being registered. Then, ''message_handler()'' is called on all already registered Zend extensions, and is given as argument the pointer to the being-registered extension.
 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. 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.
  
Line 225: Line 225:
    At this stage, the extensions order is not relevant. Extensions are simply registered, nothing more will happen here    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 registration is quite the same as Zend extensions registration : dlopen() the shared object, and checks for compatibility.
 PHP extensions must export a ''get_module'' symbol. Note that this is different from Zend extensions. Zend extensions required that two symbols exist in the .so file, and those two symbols were structures. PHP extensions on their side only require one symbol to be declared, ''get_module'', and it will get casted as a function returning the ''zend_module_entry'' pointer. PHP extensions must export a ''get_module'' symbol. Note that this is different from Zend extensions. Zend extensions required that two symbols exist in the .so file, and those two symbols were structures. PHP extensions on their side only require one symbol to be declared, ''get_module'', and it will get casted as a function returning the ''zend_module_entry'' pointer.
  
Line 243: Line 243:
  
 After that, the loading mechanism fills in the ''module_number'' field from the PHP extension with just an integer that gets incremented by one at every PHP extension registration/load. After that, the loading mechanism fills in the ''module_number'' field from the PHP extension with just an integer that gets incremented by one at every PHP extension registration/load.
-Now the PHP extension is going to be registered into a shared global variable, called ''module_registry'', beeing of type HashTable. +Now the PHP extension is going to be registered into a shared global variable, called ''module_registry'', being of type HashTable. 
-The registration step will perform two checks against the PHP extension beeing registered :+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   * If the PHP extension is already present in the registry, warning then failure at registration
   * PHP extension dependencies **conflicts only** are checked   * PHP extension dependencies **conflicts only** are checked
Line 252: Line 252:
   * A PHP extension can tell the system that it requires another PHP extension to be loaded before itself   * 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.+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'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. 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've been declared in php.ini** **PHP extensions will be registered in the exact same order they've been declared in php.ini**
Line 264: Line 264:
 It checks the extension field ''module_started'' , just a flag not to activate the same extension more than once. It then checks dependencies against requirements. If an extension requires another to be registered before itself and it's not the case, then an error will show up. It checks the extension field ''module_started'' , just a flag not to activate the same extension more than once. It then checks dependencies against requirements. If an extension requires another to be registered before itself and it's not the case, then an error will show up.
    Note that conflicts requirements have already been checked against, at extension loading (see last chapter)    Note that conflicts requirements have already been checked against, at extension loading (see last chapter)
-After that, the extension globals are registered (call to ''globals_ctor()'' on the extension) and ''module_startup_func()'' is called on the extension, this is known as beeing the "MINIT process"+After that, the extension globals are registered (call to ''globals_ctor()'' on the extension) and ''module_startup_func()'' is called on the extension, this is known as being the "MINIT process"
  
 ==== Activating Zend extensions ==== ==== Activating Zend extensions ====
Line 271: Line 271:
    Remember that Zend extensions are never sorted in any way. You must then declare them in the FIFO order in php.ini. The engine wont touch your declaration order    Remember that Zend extensions are never sorted in any way. You must then declare them in the FIFO order in php.ini. The engine wont touch your declaration order
 ''zend_extension_startup()'' just calls for the ''startup()'' function on Zend extensions, and appends a declaration message in the Zend phpinfo() message "With module XXX" showing to end user the Zend extension is both registered, and activated. ''zend_extension_startup()'' just calls for the ''startup()'' function on Zend extensions, and appends a declaration message in the Zend phpinfo() message "With module XXX" showing to end user the Zend extension is both registered, and activated.
-   Dont be fooled here, it's not the activate() function wich is triggered from Zend extensions, but the startup() function+   Don'be fooled here, it's not the activate() function which is triggered from Zend extensions, but the startup() function
  
 ===== Extensions lifetime ===== ===== Extensions lifetime =====
Line 279: Line 279:
 ==== Request startup ==== ==== Request startup ====
 Zend extensions come first, and their ''activate()'' function is called Zend extensions come first, and their ''activate()'' function is called
-PHP extensions come second, and their ''request_startup_func()'' is called, this is known as beeing the "RINIT" stage+PHP extensions come second, and their ''request_startup_func()'' is called, this is known as being the "RINIT" stage
  
 ==== Request shutdown ==== ==== Request shutdown ====
-PHP extensions come first, and their ''request_shutdown_func()'' is called, this is known as beeing the "RSHUTDOWN" stage+PHP extensions come first, and their ''request_shutdown_func()'' is called, this is known as being the "RSHUTDOWN" stage
 Zend extensions come after, and their ''deactivate()'' function is called Zend extensions come after, and their ''deactivate()'' function is called
 A third hook is called : ''post_deactivate_func()'', for each PHP extensions. PHP extensions are here given a chance to do some work after Zend extensions have all shut down A third hook is called : ''post_deactivate_func()'', for each PHP extensions. PHP extensions are here given a chance to do some work after Zend extensions have all shut down
Line 288: Line 288:
 ==== PHP shutdown ==== ==== 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 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 functionnalities. As the ''module_registry'' containing all the PHP extensions is a Hashtable, when it is constructed for the first time, a destructor is registered. This one is called here. It is ''module_destructor()''+PHP extensions are first destroyed. This is done internally by relying on the Hashtable functionalities. As the ''module_registry'' containing all the PHP extensions is a Hashtable, when it is constructed for the first time, a destructor is registered. This one is called here. It is ''module_destructor()''
 It calls ''module_shutdown_func()'' on each extension, this is called the "MSHUTDOWN" stage. Then it destroys the extension globals calling ''globals_dtor()'' and finally it unregisters the PHP functions the extension may have registered at startup. It calls ''module_shutdown_func()'' on each extension, this is called the "MSHUTDOWN" stage. Then it destroys the extension globals calling ''globals_dtor()'' and finally it unregisters the PHP functions the extension may have registered at startup.
 Finally, if the extension were to be loaded with ''dlopen()'' (not a statically compiled extension), it is then dlunload()'ed except if the env variable ZEND_DONT_UNLOAD_MODULES is used (usefull for debugging modules with valgrind, for example) Finally, if the extension were to be loaded with ''dlopen()'' (not a statically compiled extension), it is then dlunload()'ed except if the env variable ZEND_DONT_UNLOAD_MODULES is used (usefull for debugging modules with valgrind, for example)
internals/extensions.1365606531.txt.gz · Last modified: 2017/09/22 13:28 (external edit)