PHP interpreter engine execution process catalogue
1. SAPI interface 2. explain the execution script process in php cli Mode 3. PHP Zend Complile/Execute function interface (Hook Call architecture basics)
1. SAPI interface
The SAPI layer of PHP encapsulates upper-layer interfaces so that PHP can be used in many scenarios (such as apache, ningx, cgi, fastcgi, and cli ), take cli SAPI as an example to learn how the PHP interpreter engine processes the Cli (Command Line Interface) of the PHP user-state source code file, that is, the PHP Command Line mode. now this SAPI is installed by default, after installing PHP on the server, an executable file is usually generated.
Script execution starts with the implementation of SAPI. Only different SAPI implementations will complete their specific work. for example, the mod_php SAPI implementation of Apache needs to initialize some information obtained from Apache. in the output content, the content is returned to Apache, other SAPI implementations are similar.
0x1: sapi_module_struct
To define an SAPI, first define a sapi_module_structPHP-SRC/sapi/cli/php_cli.c
/* {Sapi_module_struct cli_sapi_module */static sapi_module_struct cli_sapi_module = {"cli",/* name php_info () is used */"Command Line Interface ", /* pretty name */php_cli_startup,/* startup */restart,/* shutdown */NULL,/* activate */sapi_cli_deactivate,/* deactivate */sapi_cli_ub_write, /* unbuffered write */sapi_cli_flush,/* flush */NULL,/* get uid */NULL,/* getenv */php_error,/* error handler */sapi_cli_header_handler, /* header handler */sapi_cli_send_headers,/* send headers handler */sapi_cli_send_header,/* send header handler */NULL,/* read POST data */sapi_cli_read_cookies, /* read Cookies */sapi_cli_register_variables,/* register server variables */sapi_cli_log_message,/* Log message */NULL,/* Get request time */NULL, /* Child terminate */STANDARD_SAPI_MODULE_PROPERTIES };/*}}}*/
This structure contains some constants, such as name, which will be used when we call php_info. Some initialization and final functions, as well as some function pointers, are used to tell Zend how to obtain and output data. in the following process, fields are involved one by one.
Relevant Link:
http://www.nowamagic.net/librarys/veda/detail/1285
2. explain the script execution process in php cli mode
0x1: Process Startup
After some necessary initialization, the main process enters the logic process of SAPI and initializes some environment variables, which will take effect throughout the SAPI lifecycle.
0x2: MINIT
After entering the specific SAPI mode, PHP calls the MINIT method \ php-5.6.17 \ sapi \ cli \ php_cli.c of each extension
int main(int argc, char *argv[]){ .. sapi_module_struct *sapi_module = &cli_sapi_module; .. sapi_module->ini_defaults = sapi_cli_ini_defaults; sapi_module->php_ini_path_override = ini_path_override; sapi_module->phpinfo_as_text = 1; sapi_module->php_ini_ignore_cwd = 1; sapi_startup(sapi_module); sapi_started = 1; ..
Php_cli_startup
static int php_cli_startup(sapi_module_struct *sapi_module) /* {{{ */{ if (php_module_startup(sapi_module, NULL, 0)==FAILURE) { return FAILURE; } return SUCCESS;}
PHP calls the MINIT method of each extension to switch these extensions to the available state.
/* {{{ php_module_startup */int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules){ .. zend_module_entry *module; .. module_shutdown = 0; module_startup = 1; sapi_initialize_empty_request(TSRMLS_C); sapi_activate(TSRMLS_C); .. /* start additional PHP extensions */ php_register_extensions_bc(additional_modules, num_additional_modules TSRMLS_CC); /* load and startup extensions compiled as shared objects (aka DLLs) as requested by php.ini entries theese are loaded after initialization of internal extensions as extensions *might* rely on things from ext/standard which is always an internal extension and to be initialized ahead of all other internals */ php_ini_register_extensions(TSRMLS_C); zend_startup_modules(TSRMLS_C); /* start Zend extensions */ zend_startup_extensions(); ..
MINIT indicates "module initialization ". Each module defines a set of functions, class libraries, and so on to process other requests. a typical MINIT method is as follows:
PHP_MINIT_FUNCTION(extension_name){ /* Initialize functions, classes etc */ }
0x3: RINIT
When a page request occurs, the SAPI layer gives control to the PHP layer. Therefore, PHP sets the environment variables required to reply to this request. It also creates a variable table to store the names and values of variables generated during execution. PHP calls the RINIT method of each module, that is, "Request Initialization"
A classic example is the Session module RINIT. if the Session module is enabled in ini, the $ _ SESSION variable will be initialized when the RINIT of this module is called, and the related content will be read.
The RINIT method can be considered as a preparation process, which is automatically started before the program is executed. A typical RINIT method is as follows:
PHP_RINIT_FUNCTION(extension_name) { /* Initialize session variables,pre-populate variables, redefine global variables etc */ }
PHP processes initialization and resource allocation transactions during each request. This part is defined by the activate field. from the above structure, we can see that the cli_sapi_module struct corresponding to the above cli does not provide initialization processing handle for CGI. For mod_php, it is different. he wants to register resource destructor, apply for space, initialize environment variables, and so on in the apache pool.
0x4: SCRIPT
PHP uses php_execute_script (& file_handle TSRMLS_CC) to execute PHP scripts \ php-5.6.17 \ main. c
/* {Php_execute_script */PHPAPI int php_execute_script (zend_file_handle * primary_file TSRMLS_DC) {// The file_handle type is zend_file_handle, which encapsulates zend's file handle, zend_file_handle * prepend_file_p, * append_file_p; zend_file_handle prepend_file = {0}, append_file = {0 };.. // php_execute_script is finally called using retval = (zend_execute_scripts (ZEND_REQUIRE TSRMLS_CC, NULL, 3, prepend_file_p, primary_file, append_file_p) = SUCCESS );..
Php_execute_script is the zend_execute_scripts {PHPSRC}/Zend/zend. c
// This function has variable parameters. you can execute multiple php files ZEND_API int zend_execute_scripts (int type TSRMLS_DC, zval ** retval, int file_count,...) at a time ,...) /*{{{*/{.. EG (active_op_array) = zend_compile_file (file_handle, type TSRMLS_CC );.. if (EG (active_op_array) {EG (return_value_ptr_ptr) = retval? Retval: NULL; zend_execute (EG (active_op_array) TSRMLS_CC );..
1. compile compilation process
Zend_compile_file is a function pointer, which is declared in {PHPSRC}/Zend/zend_compile.c
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
During engine initialization, the address of the compile_file function is assigned to zend_compile_file. the compile_file function is defined in {PHPSRC}/Zend/zend_1_age_scanner.l.
// The function uses the zend_file_handle pointer as the parameter and returns a ZEND_API zend_op_array * compile_file (optional * file_handle, int type TSRMLS_DC) {.. // Lex lexical parsing process ..
2. execute the execution process (execute opcode one by one)
Zend_execute is also a function pointer (opcode array obtained through the compile process), which is declared in {PHPSRC}/Zend/zend_execute.c
ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);
During engine initialization, the address of the execute function is assigned to zend_execute. The definition of execute is {PHPSRC}/Zend/zend_vm_execute.h.
// Zend_execute uses a pointer pointing to the zend_op_array structure as the parameter. this pointer is the returned value of zend_compile_file. zend_execute starts to execute the op code in op_array. during the execution of op code, various PHP functions are implemented: ZEND_API void zend_execute (zend_op_array * op_array TSRMLS_DC) {if (EG (exception) {return;} zend_execute_ex (cursor (op_array, 0 TSRMLS_CC) TSRMLS_CC );}
0x5: RSHUTDOWN
Once the page is executed (whether it is executed at the end of the file or aborted using the exit or die function), PHP starts the cleanup program. It calls the RSHUTDOWN method of each module in sequence. RSHUTDOWN is used to clear the symbol table generated when the program is running, that is, to call the unset function for each variable.
PHP_RSHUTDOWN_FUNCTION(extension_name) { /* Do memory management, unset all variables used in the last PHP call etc */ }
0x6: MSHUTDOWN
Finally, all requests have been processed, and the SAPI is also ready to be closed. PHP starts to execute Step 2: PHP calls the MSHUTDOWN method of each extension, which is the last chance for each module to release the memory.
PHP_MSHUTDOWN_FUNCTION(extension_name) { /* Free handlers and persistent memory etc */ }
/Main. c
/* {{{ php_module_shutdown_wrapper */int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals){ TSRMLS_FETCH(); php_module_shutdown(TSRMLS_C); return SUCCESS;}
Relevant Link:
http://www.nowamagic.net/librarys/veda/detail/1286http://www.nowamagic.net/librarys/veda/detail/1322http://www.nowamagic.net/librarys/veda/detail/1323http://www.nowamagic.net/librarys/veda/detail/1332http://blog.csdn.net/phpkernel/article/details/5716342http://www.nowamagic.net/librarys/veda/detail/1287http://www.nowamagic.net/librarys/veda/detail/1289
3. PHP Zend Complile/Execute function interface (Hook Call architecture basics)
When designing the architecture implementation, the PHP kernel not only provides the extension mechanism, but also provides the Hook mechanism for two key Zend processes (compile and execute, PHP extension developers can Hook and hijack the Zend compilation/interpretation execution process, execute the custom code logic before Zend compilation and execution, and then return the control to Zend. When the engine is initialized (zend_startup)
1. end_execute points to the default execute2. zend_compile_file point to the default compile_file
We can rewrite zend_execute and zend_compile_file into other compilation and execution functions before the actual compilation and execution (in the RINIT phase), which leaves a hook for our extension engine, for example, a well-known extension vld for viewing PHP op code, which is in the hook function (PHP_RINIT_FUNCTION) initialized by each request, replace zend_execute and zend_compile_file with your own vld_execute and vld_compile_file. These two functions encapsulate the original functions and add additional functions for outputting opcode information, because the engine initialization occurs before the module request initialization, and the module request initialization is before compilation and execution, this overwrite can achieve the goal.
Relevant Link: Copyright (c) 2016 LittleHann All rights reserved