Start of everything: SAPI interface
SAPI (Server application programming Interface) refers to a specific application of PHP programming interface, just like a PC, no matter what operating system installed, as long as the interface specification of the PC can be run on the PC, PHP scripts can be executed in a number of ways, either through a Web server or directly under the command line or embedded in other programs.
In general, we use a Web server such as Apache or Nginx to test PHP scripts or execute them under the command line via the PHP interpreter program. When the script finishes executing, the Web server answers, the browser displays the response information, or the content is displayed on the command line standard output.
We seldom care where the PHP interpreter is. While executing scripts through the Web server and the command-line program looks very different, the workflow is actually the same. Command-line arguments are passed to the PHP interpreter to execute the script, which is equivalent to requesting a PHP page via a URL. The result of the response is returned when the script executes, except that the command line response is displayed on the terminal.
The start of the script execution begins with the SAPI interface implementation. Just different SAPI interface implementations will accomplish their specific work, such as Apache's mod_php SAPI implementations need to initialize some information obtained from Apache, the output content is to return the content to Apache, other SAPI implementations are similar.
Some of the common SAPI implementations are described in more detail in the following sections.
Start and end
PHP begins execution after two main stages: the start phase before processing the request and the end phase after the request. There are two processes in the start phase: The first process is the module initialization phase (MINIT), which is performed only once during the entire SAPI life cycle (for example, throughout the life cycle of Apache startup or during the entire execution of a command-line program). The second process is the module activation phase (RINIT), which occurs during the request phase, such as requesting a page through a URL, and module activation before each request (Rinit request starts). For example, if PHP registers some extensions, it will call back the Minit function of all modules during the Minit phase. Modules can perform some initialization work at this stage, such as registering constants, defining classes used by modules, and so on. The module implements these callback functions by following a macro when implemented:
Php_minit_function(myphpextension){ //Register constants or class initialization operations return SUCCESS}
After the request arrives, PHP initializes the basic environment for executing the script, such as creating an execution environment, including a symbol table that holds the variable name and value contents of the PHP runtime, and a symbol table for all current functions and information such as classes. PHP then invokes all of the module's Rinit functions, and at this stage each module can perform some related operations, and the module's Rinit function is similar to the Minit callback function:
Php_rinit_function(myphpextension){ ///For example, record the request start time //And then record the end time at the end of the request. So we can record the time it takes to process the request. return SUCCESS}
After the request has been processed, the end stage is reached, and the general script executes to the end, or by calling the exit () or Die () function, PHP will go to the end stage. And the beginning of the corresponding, the end stage is divided into two links, one at the end of the request to deactivate the module (Rshutdown, corresponding to Rinit), one at the end of the SAPI life cycle (Web server exit or command line script completion exit) when the module is closed (Mshutdown, Corresponds to Minit).
Php_rshutdown_function(myphpextension){ //For example, record the request end time and write the corresponding information to the date to the file. return SUCCESS}
For more information about extended development, refer to the 13th chapter, extending development
Single-Process SAPI life cycle
cli/cgi mode PHP is a single-process SAPI mode. This type of request is closed after processing a request. That is, it only passes through the following links: Start-Request Start-Request shutdown-end the SAPI interface implementation completes its life cycle. 2.1 is shown below:
Figure 2.1 Single-process SAPI life cycle
The diagram above is very simple and well understood. It's just that PHP has done a lot of work between all stages. Here are some additions:
Start
Before invoking the module initialization for each module, there is an initialization process that includes:
- Initialize a number of global variables
In most cases, the initialization global variable is set to NULL, with some exceptions, such as setting Zuf (zend_utility_functions) to Zuf.printf_function = php_printf, where the Php_ printf is assigned to zend_printf as a global function pointer in the Zend_startup function, and the zend_printf function is typically used as a regular string output, such as displaying the Debug_print_ of the program call stack BackTrace is the use of it to print related information.
- Initialize a number of constants
The constants here are some of PHP's own constants, which are either hardcoded in the program, such as Php_version, or written in a configuration header file, such as Pear_extension_dir, which is written in the Config.w32.h file.
- Initializing the Zend engine and core components
The role of the Zend_startup function mentioned earlier is to initialize the Zend engine, where the initialization includes memory management initialization, global use of function pointer initialization (as previously mentioned zend_printf, etc.), the parsing of PHP source files, syntax analysis, The intermediate code executes the function pointer assignment, initializes several hashtable (such as function table, constant table and so on), prepares for INI file parsing, prepares the PHP source file parsing, registers the built-in functions (such as strlen, define, etc.), registers the standard constants (such as E_all, TRUE , NULL, and so on), registering Globals global variables, and so on.
The role of the Php_init_config function is to read the php.ini file, set the configuration parameters, load the Zend extension, and register the PHP extension function. This function is divided into the following steps: Initialize the parameter configuration table, invoke the INI initialization configuration in the current mode, such as the CLI mode, will do the following initialization:
Ini_default("report_zend_debug" "0"); Ini_default("Display_errors" "1") ;
However, there are no such initialization operations in other modes. The next steps are to find the INI file:
- To determine if there is a php_ini_path_override, this path can be specified in CLI mode by the-c parameter (in the command parameter of PHP-C means to find the INI file in the specified path).
- If there is no php_ini_path_override, determine if the php_ini_ignore is non-null (ignoring the php.ini configuration, which is also useful in CLI mode, using the-n parameter).
- If you do not ignore the INI configuration, start processing Php_ini_search_path (Find the path to the INI file) that includes CWD (the current path, but this does not work with CLI mode), the directory where the script is executed, the environment variable path and the PHPRC, and the PHP in the configuration file The value of the _config_file_path.
- After the lookup path is ready, PHP will determine if the current INI path (php_ini_file_name) is a file and whether it can be opened. If the INI path is a file and can be opened, this file is used, that is, the INI file specified by the-c parameter in CLI mode is the highest priority, followed by the file specified by PHPRC, and the third is to find php-%sapi-module-name% in the search path. INI file (such as in CLI mode should look for the Php-cli.ini file), and finally the search path to find the php.ini file.
- Initialization of global operation functions
The Php_startup_auto_globals function initializes some global variables that are used very frequently in user space, such as $_get, $_post, $_files, and so on. This is only initialized, and the Zend_register_auto_global function that is called is simply adding these variable names to the table of variables for CG (auto_globals).
The Php_startup_sapi_content_types function is used to initialize the SAPI function for different types of content, where the processing functions include the post data default handler, the default data processing function, and so on.
- Initializing statically built modules and shared modules (Minit)
The Php_register_internal_extensions_func function is used to register statically constructed modules, which are also the default loaded modules that we can think of as built-in modules. The modules built into the PHP5.3.0 version include the PHP standard extension module (/ext/standard/directory, which is the most frequently used function, such as String functions, mathematical functions, array manipulation functions, etc.), calendar extensions, FTP extensions, session extensions, and so on. These built-in modules are not immutable, in different PHP templates, due to different time requirements or other factors will cause these default loaded modules will change, such as from the code we can see the MySQL, XML and other extension modules have been or will appear as built-in modules.
Module initialization performs two operations: 1. Register these modules to the list of registered modules (Module_registry), if the registered module has been registered, PHP will report module XXX already loaded error. 1. Register the functions contained in each module with the function table (CG (function_table)), and if the function cannot be added, the unable to register functions is reported, unable to load.
After registering the statically constructed module, PHP registers the additional modules, which can load different sets of modules in different modes, such as without these additional modules in CLI mode.
After the built-in modules and add-ons, the next step is to register extensions that are flexibly configured through shared objects (such as DLLs) and php.ini files.
After all the modules have been registered, PHP will execute the module initialization operation (Zend_startup_modules) immediately. The whole process is to iterate through each module sequentially, invoking the module initialization function of each module, which is what is contained in the macro php_minit_function, as described earlier in this section.
- disabling functions and Classes
The Php_disable_functions function is used to disable some functions of PHP. These disabled functions come from the disable_functions variable of the PHP configuration file. Its disabling procedure is to call the Zend_disable_function function to remove the specified function name from the CG (function_table) function table.
The Php_disable_classes function is used to disable some classes of PHP. These disabled classes are derived from the PHP disable_classes variable of the configuration file. Its disabling procedure is to call the Zend_disable_class function to remove the specified class name from the CG (Class_table) class table.
ACTIVATION
In processing the file-related content, PHP invokes php_request_startup for the request initialization operation. The request initialization operation, in addition to the diagram shown in the call of each module's request initialization function, but also do a lot of other work, the main content is as follows:
- Activating the Zend Engine
The Gc_reset function is used to reset the garbage collection mechanism, of course, after PHP5.3.
The Init_compiler function is used to initialize the compiler, such as emptying an array of opcode during compilation, preparing the data structure for compilation, and so on.
The Init_executor function is used to initialize the intermediate code execution process. During compilation, the list of functions, the list of classes, etc. are stored in the global variables at compile time, and the lists are assigned to the global variables to be executed when the process is ready for execution, such as: EG (function_table) = CG (function_table); Intermediate code execution is performed in the PHP execution virtual stack, and these stacks will be initialized together when initialized. In addition to the stack, there are symbol tables (eg (symbol_table) that store variables that are initialized to the hashtable of 50 elements, and the eg (Objects_store) that holds the object is initialized with 1024 elements. PHP Execution Environment In addition to some of the above variables, there are error handling, exception handling, and so on, these are initialized here. The zend_extensions that is configured through PHP.ini is also here to be traversed by calling the Activate function.
The Sapi_activate function initializes the SG (sapi_headers) and SG (REQUEST_INFO) and sets some content for the HTTP request method, such as setting the SG (REQUEST_INFO) When the request method is head. Headers_only=1; One of the most important operations of this function is to process the requested data, which will eventually call Sapi_module.default_post_reader. and Sapi_module.default_post_reader in front of the module initialization is the default handler function registered by the Php_startup_sapi_content_types function as Main/php_content_ The Php_default_post_reader function in the types.c file. This function writes the original data of the POST to the $http_raw_post_data variable.
After processing the post data, PHP reads the value of the cookie through sapi_module.read_cookies, and in CLI mode, the function is implemented as sapi_cli_read_cookies, and there is only one return in the function body NULL;
If the Activate function is set in the current mode, run this function to activate SAPI, which is set to NULL in CLI mode.
- Environment initialization
The environment initialization here is the initialization of some environment variables that need to be used in the user space, the environment includes the server environment, the request data environment and so on. The actual variables we use are $_post, $_get, $_cookie, $_server, $_env, and $_files. As with Sapi_module.default_post_reader, the value of Sapi_module.treat_data is also when the module is initialized by Php_startup_sapi_content_ The types function registers the default data processing function for the Php_default_treat_data function in the main/php_variables.c file.
In $_cookie, for example, the Php_default_treat_data function splits all cookies and assigns them to the corresponding variable based on the delimiter.
- Module Request Initialization
PHP uses the Zend_activate_modules function to initialize the request of the module, which is what we see in the figure called each extension ' s rinit. This function calls its Rinit method to implement the request initialization operation of the module by traversing all the modules registered in the Module_registry variable.
Run
The Php_execute_script function contains all the procedures for running a PHP script.
When a PHP file needs to be parsed, it may need to execute three files, including a pre-execute file, the main file that is currently required to execute, and a post-execute file. Non-current two files can be set in the php.ini file via the Auto_prepend_file parameter and the Auto_append_file parameter. If these two parameters are set to NULL, the corresponding execution file is disabled.
For files that need to be parsed, the Zend_compile_file (Compile_file function) performs lexical parsing, parsing, and intermediate code generation operations, returning all the intermediate code for this file. If the parsed file has a valid intermediate code generated, call Zend_execute (Execute function) to execute the intermediate code. These exception handlers are called if an exception occurs during execution and the user has defined the handling of these exceptions. After all the operations have been processed, PHP returns the results via eg (RETURN_VALUE_PTR_PTR).
Deactivation
The process of closing a request for PHP is a collection of several close operations that exist in the Php_request_shutdown function. This collection includes the following:
- Call all functions registered through Register_shutdown_function (). These functions, which are called at shutdown, are added in user space. A simple example, we can call a unified function when the script is wrong, give the user a friendly page, which is somewhat similar to the 404 pages in the page.
- Executes all the available __destruct functions. The destructor here includes destructors for all objects in the object pool (eg (objects_store) and the destructor for each element in eg (symbol_table).
- Brush out all the output.
- Sends an HTTP reply header. This is also the process of outputting a string, except that the string may conform to certain specifications.
- Traverse the close request method of each module, execute the request shutdown operation of the module, this is the call each extension ' s rshutdown we see in the diagram.
- Destroys a variable of the global variable table (PG (http_globals)).
- Close the lexical parser, parser, and intermediate code executor with the Zend_deactivate function.
- Call each extension's Post-rshutdown function. Only the basic Post_deactivate_func function pointers for each extension are null.
- Close the SAPI and destroy the contents of SG (sapi_headers), SG (REQUEST_INFO), etc. by Sapi_deactivate.
- Closes the wrapper for the stream, closes the filter for the stream.
- Turn off memory management.
- Reset Maximum Execution time
End
Finally, it's the place to finish.
Sapi_flush will refresh the final content. It is called Sapi_module.flush, which is equivalent to the Fflush function in CLI mode.
Zend_shutdown will shut down the Zend engine.
In this case the process in the diagram, we should be performing each module of the shutdown module operation. There is only one Zend_hash_graceful_reverse_destroy function that will destroy the module_registry. Of course, it is finally called the method of closing the module, which is rooted in the initialization of the module_registry when the hash table is set to call the Zend_module_dtor macro when the destructor. The Zend_module_dtor macro corresponds to the Module_destructor function. In this function, the module's Module_shutdown_func method is called, that is, the function that the Php_rshutdown_function macro produces.
After closing all modules, PHP continues to destroy global function tables, destroy global class tables, sell global variable tables, and so on. The shutdown function of each extension is called by traversing all elements of zend_extensions through zend_shutdown_extensions.
Multi-process SAPI life cycle
PHP is usually compiled as a module of Apache to handle PHP requests. Apache will generally use multi-process mode, Apache will fork out many sub-processes, each process of memory space Independent, each sub-process will go through the start and end links, but the beginning of each process only after the process fork out, Multiple requests may be processed throughout the lifetime of the process. The shutdown phase occurs only when Apache is closed or the process is ended, and between these two phases begins with each request repeating the request-the link of the request shutdown. 2.2 is shown below:
Figure 2.2 SAPI life cycle of multi-process SAPI life cycle multithreading
Multithreaded mode is similar to a process in a multi-process, but differs in the process's lifetime by repeatedly requesting the start-Request shutdown link
Figure 2.3 Multi-threaded SAPI life cycle Zend Engine
The Zend engine is the core of the PHP implementation and provides the infrastructure for language implementations. For example: PHP syntax implementation, script compiler run environment, extension mechanism and memory management, of course, here PHP refers to the official PHP implementation (in addition to the official implementation, is now more well-known Facebook hiphop implementation, but so far, PHP does not yet have a standard language specification, while PHP provides the interface for request processing and other Web servers (SAPI).
The current PHP implementation and Zend engine is very close, even some too close, for example, many PHP extensions are used by the Zend API, and Zend is the implementation of the PHP language itself, PHP just use Zend This kernel to build the PHP language, The PHP extension mostly uses the Zend API, which leads to a lot of PHP extension and Zend engine coupling together, when I write this book, the PHP core developers proposed to untie this coupling,
There is no doubt about the popularity of PHP at the moment, and any popular language will often appear in other implementations of the language, which is evident in the Java community, where there are already a lot of JVM-based languages, such as IBM's Project Zero, which implements a JVM-based PHP implementation , . NET also have similar implementations, usually they do this because they like the language, but do not want to abandon the original platform, or the existing language implementation is not satisfied with the performance or language characteristics (hiphop is born).
Many scripting languages have a language extension mechanism, the PHP extension is usually through the pear library or native extension, in Ruby, the boundary is not very obvious, they will even provide two sets of implementations, one is mainly used in the environment can not be compiled, and in the appropriate environment using the C implementation of the native extension, This can be guaranteed in both efficiency and portability. These extensions that are currently written for PHP are often not reusable in other PHP implementations, and the hiphop approach is to rewrite the most popular extensions. If the PHP extension can be decoupled from ZENDAPI, it will be easier to reuse these extensions in other languages.
Section I life cycle and Zend engine