In this article, we will study how PHP code is interpreted and executed and the life cycle of PHP script running.
Overview
Startup of PHP service. Strictly speaking, PHP-related processes do not need to be started manually. They run when Apache starts. Of course, if you need to restart the PHP service, you can also restart the PHP service manually. For example, after updating the code in a formal environment with opcode enabled, you need to restart PHP to recompile the PHP code.
From a macro perspective, the implementation of the PHP kernel is to receive input data, perform corresponding processing internally, and then output the results. For the PHP kernel, the PHP code we write is the input data received by the kernel. After receiving the code data, the PHP kernel performs code analysis and operation execution on the code we wrote, and finally returns the corresponding operation result.
However, unlike the usual C language code, to execute PHP code, you first need to "translate" the PHP code into machine language to perform the corresponding function. To perform the "translation" step, the PHP kernel is required to perform: lexical analysis, syntax analysis and other steps. Finally, it is handed over to the Zend Engine of the PHP kernel for sequential execution.
Lexical Analysis
Separate PHP code into "units" (TOKEN)
Syntax analysis
Convert "units" into Zend Engine executable operations
Zend Engine execution
Execute the operations obtained by syntax analysis in sequence
All PHP programs (CGI/CLI) start with the SAPI (Server Application Programming Interface) interface. SAPI refers to the programming interface for specific PHP applications. For example, Apache's mod_php.
After PHP starts executing, it will go through two main stages: the starting stage before processing the request and the ending stage after the request.
Starting phase
The entire initial stage of PHP will go through two stages: module initialization and module activation.
MINIT
That is, the module initialization phase, which occurs during the entire life cycle after the startup of Apache/Nginx or the entire execution process of the command line program. This phase only occurs once
RINIT
Module activation occurs during the request phase. Do some initialization work: such as registering constants, defining classes used by the module, etc.
The module can implement these callback functions through the following macros during implementation:
PHP_MINIT_FUNCTION(myphpextension) { //注册常量或者类等初始化操作 return SUCCESS; } PHP_RINIT_FUNCTION(myphpextension) { //例如记录请求开始时间 //随后在请求结束的时候记录结束时间。这样我们就能够记录处理请求所花费时间了 return SUCCESS; }
After the PHP script request is processed, it enters the end phase. Generally, PHP enters the end phase when the script is executed to the end or the exit or die function is called.
End stage
The end phase of PHP is divided into two parts: deactivating the module and closing the module.
RSHUTDOWN
Disable module (corresponds to RINIT)
MSHUTDOWN
Close the module (corresponding to MINIT)
CLI/CGI mode PHP belongs to the single-process SAPI mode. This means that the PHP script is closed after being executed once, and all variables and functions cannot be used anymore. That is, in CGI mode, variables of the same php file cannot be used in other php files.
Let’s use an example to look at the SAPI life cycle of single-threaded PHP.
Single-threaded SAPI life cycle
For example:
php -f test.php
Call the MINIT module of each extension to initialize
Request test.php
Call the RINIT module of each extension to activate
Execute test.php
Call the RSHUTDOWN deactivation module of each extension
Execution completed Clean up variables and memory after test.php
Call MSHUTDOWN of each extension, close the module
Stop PHP execution
The above is a simple execution process, and some additions will be made below.
PHP will have an initialization process before calling the module initialization of each module, including:
Initializing several global variables
In most cases, setting them is NULL.
Initialize several constants
The constants here are some of PHP’s own constants.
Initialize Zend engine and core components
The initialization operations here include memory management initialization, global function pointer initialization, and functions for lexical analysis, syntax analysis, and intermediate code execution of PHP source files. Assign pointers, initialize several HashTables (such as function tables, constant tables, etc.), prepare for ini file parsing, prepare for PHP source file parsing, register built-in functions, standard constants, GLOBALS global variables, etc.
Parse php.ini
Read php.ini file, set configuration parameters, load zend extension and register PHP extension function.
Initialization of global operation functions
Initialize some global variables that are frequently used in user space, such as: $_GET, $_POST, $_FILES, etc.
初始化静态构建的模块和共享模块(MINIT)
初始化默认加载的模块。
模块初始化执行操作:
将模块注册到已注册模块列表
将每个模块中包含的函数注册到函数表
禁用函数和类
会调用zend_disable_function函数将PHP的配置文件中的disable_functions变量代表的函数从CG(function_table)函数表中删除。
激活Zend引擎
使用init_compiler函数来初始化编译器。
激活SAPI
使用sapi_activate函数来初始化SG(sapi_headers)和SG(request_info),并且针对HTTP请求的方法设置一些内容。
环境初始化
初始化在用户控件需要用到的一些环境变量。包括服务器环境、请求数据环境等。
模块请求初始化
PHP调用zend_activate_modules函数遍历注册在module_registry变量中的所有模块,调用其RINIT方法方法实现模块的请求初始化操作。
在处理了文件相关的内容后,PHP会调用php_request_startup做请求初始化操作:
<p> 激活Zend引擎<br /> 激活SAPI<br /> 环境初始化<br /> 模块请求初始化</p>
代码的运行
以上所有准备工作完成后,就开始执行PHP程序。PHP通过zend_compile_file做词法分析、语法分析和中间代码生成操作,返回此文件的所有中间代码。如果解析的文件有生成有效的中间代码,则调用zend_excute执行中间代码。。如果在执行过程中出现异常并且用户有定义对这些异常的处理,则调用这些异常处理函数。在所有的操作都处理完后,PHP通过EG(return_value_ptr_ptr)返回结果。
DEACTIVATION(关闭请求)
PHP关闭请求的过程是一个若干个关闭操作的集合,这个集合存在于php_request_shutdown函数中。这个包括:
<p>调用所有通过register_shutdown_function()注册的函数。这些在关闭时调用的函数是在用户空间添加进来的。<br />执行所有可用的__destruct函数。这里的析构函数包括在对象池(EG(objects_store)中的所有对象的析构函数以及EG(symbol_table)中各个元素的析构方法。 <br />将所有的输出刷出去。 <br />发送HTTP应答头。<br />销毁全局变量表(PG(http_globals))的变量。 <br />通过zend_deactivate函数,关闭词法分析器、语法分析器和中间代码执行器。 <br />调用每个扩展的post-RSHUTDOWN函数。只是基本每个扩展的post_deactivate_func函数指针都是NULL。 <br />关闭SAPI,通过sapi_deactivate销毁SG(sapi_headers)、SG(request_info)等的内容。 <br />关闭流的包装器、关闭流的过滤器。 <br />关闭内存管理。 <br />重新设置最大执行时间 </p>
结束
PHP结束一个进程是,会调用sapi_flush函数将最后的内容刷新出去。然后调用zend_shutdown函数关闭Zend引擎。
参考:[http://www.php-internals.com/book/](http://www.php-internals.com/book/)