Starting Up and Shutting Down
This startup and shutdown process happens in two separate startup phases and two separate shutdown phases. One cycle is for the PHP interpreter as a whole to perform an initial setup of structures and values that will persist for the life of the SAPI. The second is for transient settings that only last as long as a single page request.
During the initial startup, before any request has been made, PHP calls every extension's MINIT (Module Initialization) method. Here, extensions are expected to declare constants, define classes, and register resource, stream, and filter handlers that all future script requests will use. Features such as these, which are designed to exist across all requests, are referred to as being persistent.
A common MINIT method might look like the following:
/* Initialize the myextension module * This will happen immediately upon SAPI startup */ PHP_MINIT_FUNCTION(myextension) { /* Globals: Chapter 12 */ #ifdef ZTS ts_allocate_id(&myextension_globals_id, sizeof(php_myextension_globals), (ts_allocate_ctor) myextension_globals_ctor, (ts_allocate_dtor) myextension_globals_dtor); #else myextension_globals_ctor(&myextension_globals TSRMLS_CC); #endif /* REGISTER_INI_ENTRIES() refers to a global * structure that will be covered in * Chapter 13 "INI Settings" */ REGISTER_INI_ENTRIES(); /* define('MYEXT_MEANING', 42); */ REGISTER_LONG_CONSTANT("MYEXT_MEANING", 42, CONST_CS | CONST_PERSISTENT); /* define('MYEXT_FOO', 'bar'); */ REGISTER_STRING_CONSTANT("MYEXT_FOO", "bar", CONST_CS | CONST_PERSISTENT); /* Resources: chapter 9 */ le_myresource = zend_register_list_destructors_ex( php_myext_myresource_dtor, NULL, "My Resource Type", module_number); le_myresource_persist = zend_register_list_destructors_ex( NULL, php_myext_myresource_dtor, "My Resource Type", module_number); /* Stream Filters: Chapter 16 */ if (FAILURE == php_stream_filter_register_factory("myfilter", &php_myextension_filter_factory TSRMLS_CC)) { return FAILURE; } /* Stream Wrappers: Chapter 15 */ if (FAILURE == php_register_url_stream_wrapper ("myproto", &php_myextension_stream_wrapper TSRMLS_CC)) { return FAILURE; } /* Autoglobals: Chapter 12 */ #ifdef ZEND_ENGINE_2 if (zend_register_auto_global("_MYEXTENSION", sizeof("_MYEXTENSION") - 1, NULL TSRMLS_CC) == FAILURE) { return FAILURE; } zend_auto_global_disable_jit ("_MYEXTENSION", sizeof("_MYEXTENSION") - 1 TSRMLS_CC); #else if (zend_register_auto_global("_MYEXTENSION", sizeof("_MYEXTENSION") - 1 TSRMLS_CC) == FAILURE) { return FAILURE; } #endif return SUCCESS; }
After a request has been made, PHP sets up an operating environment including a symbol table (where variables are stored) and synchronizes per-directory configuration values. PHP then loops through its extensions again, this time calling each one's RINIT (Request Initialization) method. Here, an extension may reset global variables to default values, prepopulate variables into the script's symbol table, or perform other tasks such as logging the page request to a file. RINIT can be thought of as a kind of auto_prepend_file directive for all scripts requested.
An RINIT method might be expected to look like this:
/* Run at the start of every page request */ PHP_RINIT_FUNCTION(myextension) { zval *myext_autoglobal; /* Initialize the autoglobal variable * declared in the MINIT function * as an empty array. * This is equivalent to performing: * $_MYEXTENSION = array(); */ ALLOC_INIT_ZVAL(myext_autoglobal); array_init(myext_autoglobal); zend_hash_add(&EG(symbol_table), "_MYEXTENSION", sizeof("_MYEXTENSION") - 1, (void**)&myext_autoglobal, sizeof(zval*), NULL); return SUCCESS; }
After a request has completed processing, either by reaching the end of the script file or by exiting through a die() or exit() statement, PHP starts the cleanup process by calling each extension's RSHUTDOWN (Request Shutdown) method. RSHUTDOWN corresponds to auto_append_file in much the same was as RINIT corresponds to auto_prepend_file. The most important difference between RSHUTDOWN and auto_append_file, however, is that RSHUTDOWN will always be executed, whereas a call to die() or exit() inside the userspace script will skip any auto_append_file.
Any last minute tasks that need to be performed can be handled in RSHUTDOWN before the symbol table and other resources are destroyed. After all RSHUTDOWN methods have completed, every variable in the symbol table is implicitly unset(), during which all non-persistent resource and object destructors are called in order to free resources gracefully.
/* Run at the end of every page request */ PHP_RSHUTDOWN_FUNCTION(myextension) { zval **myext_autoglobal; if (zend_hash_find(&EG(symbol_table), "_MYEXTENSION", sizeof("_MYEXTENSION"), (void**)&myext_autoglobal) == SUCCESS) { /* Do something meaningful * with the values of the * $_MYEXTENSION array */ php_myextension_handle_values(myext_autoglobal TSRMLS_CC); } return SUCCESS; }
Finally, when all requests have been fulfilled and the web server or other SAPI is ready to shut down, PHP loops through each extension's MSHUTDOWN (Module Shutdown) method. This is an extension's last chance to unregister handlers and free persistent memory allocated during the MINIT cycle.
/* This module is being unloaded * constants and functions will be * automatically purged, * persistent resources, class entries, * and stream handlers must be * manually unregistered. */ PHP_MSHUTDOWN_FUNCTION(myextension) { UNREGISTER_INI_ENTRIES(); php_unregister_url_stream_wrapper ("myproto" TSRMLS_CC); php_stream_filter_unregister_factory ("myfilter" TSRMLS_CC); return SUCCESS; }
Life Cycles
|