【PHP7内核剖析】-1.2 执行流程

1.2 执行流程

PHP的核心设计遵循着清晰的启动-处理-关闭的生命周期。这个生命周期根据PHP的运行模式(如CLI、FPM、Apache模块等)略有不同,但其核心阶段是一致的。理解这些阶段是深入理解PHP内核的基石。

PHP的生命周期:

一个完整的PHP生命周期主要包括以下五个核心阶段,其流程可概括为:
模块初始化阶段
MINIT 请求初始化阶段
RINIT 执行PHP脚本阶段 请求结束阶段
RSHUTDOWN 模块关闭阶段
MSHUTDOWN


1.2.1 模块初始化阶段 (MINIT)

此阶段在PHP进程启动后仅执行一次,在整个进程生命周期内永久有效。它的主要目的是初始化一些全局的、可在多个请求间共享的设施。

  • 触发时机
    • Web模式:当服务器(如Nginx+FPM)启动时,PHP解释器被加载到内存中。
    • CLI模式:每次执行一个PHP脚本时(与FPM不同,CLI通常是单请求进程)。
  • 主要工作
    1. 初始化全局变量 :初始化php.ini中定义的全局配置设置,将其存入EG(ini_directives)哈希表。
    2. 注册常量 :注册PHP内置的常量,如E_ERROR, PHP_VERSION, TRUE, FALSE等。
    3. 注册全局函数和类 :将内置的函数(如strlen, array_map)和类(如PDO, Exception)注册到全局函数表(CG(function_table))和类表(CG(class_table))中。
    4. 模块初始化 :调用所有已加载扩展(如json, pdo_mysql)的 PHP_MINIT_FUNCTION(extension_name) 钩子函数,让每个扩展执行自己的一次性初始化工作(例如,注册自己的函数、类、常量、定义资源类型等)。
    5. 初始化Zend引擎:初始化编译器、执行器等核心组件。
  • 特点 :在此阶段分配的资源是全局的,不会被请求重置。如果资源在此阶段分配,开发者必须非常小心地管理,避免造成内存泄漏或跨请求的数据污染。

1.2.2 请求初始化阶段 (RINIT)

此阶段在每个请求开始前都会被执行一次。它的目的是为即将到来的单个请求初始化一个干净、崭新的执行环境。

  • 触发时机:当一个HTTP请求到达(Web模式)或一个CLI脚本开始执行时。
  • 主要工作
    1. 初始化执行环境:重置Zend引擎的编译器、执行器状态。
    2. 初始化符号表 :初始化全局变量表($GLOBALS)和超级全局变量($_GET, $_POST, $_SERVER等),这些变量在请求开始时是空的。
    3. 设置超时时间 :根据php.ini中的max_execution_time设置脚本最大执行时间。
    4. 扩展初始化 :调用所有已加载扩展的 PHP_RINIT_FUNCTION(extension_name) 钩子函数。扩展可以在此阶段为当前请求初始化私有存储(例如,$_SESSION模块可能会在此阶段反序列化session数据)。
  • 特点 :此阶段初始化的所有内容都是请求级的,会在请求结束后被销毁和回收。

1.2.3 执行PHP脚本阶段

这是PHP核心的"工作"阶段,脚本代码在此阶段被解析、编译和执行。

  • 触发时机:在RINIT阶段完成后立即开始。
  • 主要工作
    1. 词法分析 & 语法分析 (Lexing & Parsing) :Zend引擎的编译器(zend_compile_file)读取PHP源代码,将其分解为令牌(Tokens),并根据语言规则生成抽象的语法树(Abstract Syntax Tree, AST)。PHP7的重大优化之一就是将之前的zend_language_parser.y直接生成OPCode改为先生成AST,然后再生成OPCode,允许在中间层进行更多优化。
    2. 编译 (Compilation) :遍历AST并将其转换为Zend虚拟机可执行的OPCode(操作码)。OPCode是PHP自己定义的一套中间指令集,类似于Java的字节码。
    3. 执行 (Execution) :Zend虚拟机(zend_execute)逐条执行编译生成的OPArray中的OPCode。这个虚拟机会处理所有的变量分配、函数调用、内存管理等。
      • 函数调用会进入虚拟机栈。
      • OPCode的执行可能会触发更多操作,如数据库查询、文件读写等。
  • 特点:此阶段的性能直接决定了PHP应用的快慢。OPCache等扩展的核心作用就是通过缓存第1、2步的结果(即编译好的OPCode),来避免重复的解析和编译开销。

1.2.4 请求结束阶段 (RSHUTDOWN)

此阶段在每个请求结束后执行,负责清理该请求期间分配的所有资源,为下一个请求准备好一个干净的环境。

  • 触发时机 :脚本执行完毕、主动调用exit/die或发生致命错误导致脚本终止时。
  • 主要工作
    1. 执行析构函数 :调用所有已创建对象的__destruct()方法。
    2. 刷新输出 :调用flush函数,将输出缓冲区的内容发送给客户端。
    3. 清理全局变量 :销毁在请求期间创建的所有变量(包括$_GET, $_POST等超全局变量,但它们的内存空间会被保留以供下一个请求RINIT时复用)。
    4. 关闭扩展 :调用所有已加载扩展的 PHP_RSHUTDOWN_FUNCTION(extension_name) 钩子函数。扩展可以在此阶段释放为当前请求分配的所有资源(例如,关闭数据库连接、保存session数据等)。
    5. 清理执行器:Zend引擎清理本次执行产生的所有OPCode、符号表等。
  • 特点:这是防止内存泄漏的关键阶段。所有请求级别的资源都应在此阶段被妥善释放。完成后,进程会回到RINIT阶段,等待处理下一个请求。

1.2.5 模块关闭阶段 (MSHUTDOWN)

此阶段在PHP进程终止时执行一次,是模块初始化阶段的逆过程,负责清理所有全局资源。

  • 触发时机
    • Web模式:当Web服务器被关闭或重启时(例如,重启PHP-FPM主进程)。
    • CLI模式:脚本执行结束后。
  • 主要工作
    1. 关闭扩展 :调用所有已加载扩展的 PHP_MSHUTDOWN_FUNCTION(extension_name) 钩子函数。扩展必须在此阶段注销自己注册的所有函数、类、常量,并释放所有在MINIT中分配的持久资源
    2. 清理全局配置 :销毁EG(ini_directives)哈希表,释放所有配置选项的内存。
    3. 卸载Zend引擎:清理编译器、执行器等核心组件的全局状态。
    4. 清理其他全局资源:释放所有其他在MINIT阶段分配的全局内存。
  • 特点 :此阶段是确保整个PHP进程能够干净退出、无内存泄漏的最后一道关卡。

【参考链接】https://github.com/pangudashu/php7-internal/blob/master/1/base_process.md

相关推荐
两个人的幸福8 天前
Windows 桌面应用自研 PHP 队列(下):完整代码与六大工程化优化
php
BingoGo10 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
JaguarJack10 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
用户30745969820711 天前
PHP 扩展——从入门到理解
php
鹏仔先生12 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php
云水一下12 天前
从零开始学 PHP 系列(一):PHP 的前世今生与开发环境搭建
开发语言·php
xingpanvip12 天前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
酉鬼女又兒12 天前
零基础入门计算机网络运输层:端到端通信核心作用、端口号分类规则、复用分用工作机制及UDP与TCP协议全方位对比详解
网络·网络协议·tcp/ip·计算机网络·考研·udp·php
dog25012 天前
不要再继续优化 TCP
网络协议·tcp/ip·php
Channing Lewis12 天前
PHP 解析 Excel 的那些坑:一次“行号错位”引发的数据丢失
开发语言·php·excel