php的整个生命周期被划分为以下几个阶段:
- 模块初始化阶段(modules startup)
- 请求初始化阶段(request startup)
- 执行脚本阶段(execute script)
- 请求关闭阶段(request shutdown)
- 模块关闭阶段(modules shutdown)
根据不同SAPIde实现,各阶段的执行情况会有一些差异。比如:
- cli模式下,每次执行一个脚本都会完整的经历这些阶段。
- FastCgi模式下,启动时执行一次模块初始化阶段,然后各个请求只经历请求初始化阶段、执行脚本阶段、请求关闭阶段几个阶段,在SAPI关闭时经历模块关闭阶段。各阶段执行顺序与对应的处理函数如下:
模块初始化阶段(modules startup)
这个阶段主要进行PHP框架、Zend引擎的初始化操作,入口函数为php_module_startup()。这个阶段一般只在SAPI启动时执行一次,对于Fpm而言,就是在Fpm的master进程启动时执行的。
- 激活 SAPI:sapi_activate(),初始化请求信息 SG(request_info)、设置读取 POST 请求的
- handler 等,在 module startup 阶段处理完成后将调用 sapi_deactivate()。
- 启动 PHP 输出:php_output_startup()。
- 初始化垃圾回收器:gc_globals_ctor(),分配 zend_gc_globals 内存。
- 启动 Zend 引擎:zend_startup(),主要操作包括:
- 启动内存池 start_memory_manager();
- 设置一些 util 函数句柄(如 zend_error_cb、zend_printf、zend_write 等);
- 设置 Zend 虚拟机编译、执行器的函数句柄 zend_compile_file、zend_execute_ex,以及垃圾回收的函数句柄gc_collect_cycles;
- 分配函数符号表(CG(function_table))、类符号表(CG(class_table))、常量符号表(EG(zend_constants))等,如果是多线程的话,还会分配编译器、执行器的全局变量;
- 注册 Zend 核心扩展:zend_startup_builtin_functions(),这个扩展是内核提供的,该过程将注册Zend核心扩展提供的函数,比如strlen、define、func_get_args、class_exists 等;
- 注册 Zend 定义的标准常量:zend_register_standard_constants(),比如:E_ERROR、E_WARNING、E_ALL、TRUE、FALSE 等;
- 注册$GLOBALS 超全局变量的获取 handler;
- 分配 php.ini 配置的存储符号表:EG(ini_directives)。
- 注册 PHP 定义的常量:PHP_VERSION、PHP_ZTS、PHP_SAPI,等等。
- 解析 php.ini:解析完成后所有的 php.ini 配置保存在 configuration_hash 哈希表中。
- 映射 PHP、Zend 核心的 php.ini 配置:根据解析出的 php.ini,获取对应的配置值,将最终的配置插入 EG(ini_directives)哈希表。
- 注册用于获取$_GET、$_POST、$_COOKIE、$_SERVER、$_ENV、$_REQUEST、$_FILES变量的 handler。
- 注册静态编译的扩展:php_register_internal_extensions_func()。
- 注册动态加载的扩展:php_ini_register_extensions(),将 php.ini 中配置的扩展加载到 PHP中。
- 回调各扩展定义的 module starup 钩子函数,即通过 PHP_MINIT_FUNCTION()定义的函数。
- 注册 php.ini 中禁用的函数、类:disable_functions、disable_classes。
请求初始化阶段(request startup)
这个阶段是每个请求处理前都会经历的一个阶段,对于Fpm而言,是在worker进程accept一个请求且读取、解析完请求数据后的一个阶段。这个阶段的处理函数为php_request_startup()。
主要的处理有以下几个。
- 激活输出:php_output_activate()。
- 激活 Zend 引擎:zend_activate(),主要操作如下所述。
- 重置垃圾回收器:gc_reset();
- 初始化编译器:init_compiler();
- 初始化执行器:init_executor(),将 EG(function_table)、EG(class_table)分别指向CG(function_table)、CG(class_table),所以在 PHP 的编译、执行期间,EG(function_table)与 CG(function_table)、EG(class_table)与 CG(class_table)是同一个值;另外还会初始化全局变量符号表 EG(symbol_table)、include 过的文件符号表EG(included_files);
- 初始化词法扫描器:startup_scanner()。
- 激活 SAPI:sapi_activate()。
- 回调各扩展定义的 request startup 钩子函数:zend_activate_modules()。
执行脚本阶段(execute script)
这个阶段包括php代码的编译,执行两个核心阶段,这也是Zend引擎最重要的功能。在编译阶段,php脚本将经历
php源码->抽象语法树->opline指令
的转化过程,最终生成的opline指令就是Zend引擎可以识别的执行指令,这些指令接着再被执行器执行,这就是php代码解释执行的过程。这个阶段的入口的函数为php_execute_script()。
请求关闭阶段(request shutdown)
这个阶段将flush输出内容、发送HTTP应答header头、清理全局变量、关闭编译器、关闭执行器等。另外,在该阶段将回调各个扩展的 request shutdown 钩子函数。这个阶段是请求初始化阶段的相反操作,与请求初始化时的处理一一对应。
模块关闭阶段(modules shutdown)
这个阶段在SAPI关闭时执行,与模块初始化阶段相对应。这个阶段主要是进行资源的清理、php各个模块的关闭操作,同时,将回调各个扩展的 module shutdown 钩子函数php_module_shutdown()。
本文整理于《PHP7内核剖析》
转载使用注明出处。原文链接 https://heimo-he.github.io/php/2018/04/12/php-php7-kernel-03/