PHP运行时的术语大全的庖丁解牛
2026/9/16 9:42:30 网站建设 项目流程

PHP运行时术语大全的庖丁解牛

总纲:PHP运行时 = Zend引擎内核 + SAPI接口层 + 扩展层 + 用户态业务层。
SAPI是关键:不同SAPI对应不同运行模式(FPM、CLI、CGI),直接决定整套运行时行为、生命周期、内存模型。
区分两大运行时形态:请求隔离型(FPM)、常驻内存型(Swoole‑CLI/Hyperf)

一、SAPI 层术语(最顶层入口)

  1. SAPI(Server Application Programming Interface)服务器应用程序编程接口
    根因:Zend引擎本身不负责接收HTTP、不处理网络;SAPI是PHP对外的接入层,给Zend引擎喂入输入、输出结果。不同SAPI,生命周期完全不一样。
    常见SAPI:
  • fpm‑fpm:FPM Web运行模式
  • cli:命令行脚本
  • cgi:原始CGI
  • apache2handler:老版本Apache mod_php
  • swoole:Swoole自定义SAPI(CLI下实现常驻服务)

核心:PHP本身没有Web能力,全部靠SAPI实现网络/命令行交互

  1. SG(server_globals)
    SAPI全局结构体,保存请求相关全局信息:$_SERVER、请求头、输入输出缓冲区、请求状态。
    FPM:每请求重置;
    Swoole:不能直接复用SG,改用协程上下文保存请求信息。

  2. PG(core_globals)
    PHP全局配置,对应php.ini各项配置,进程级别,整个进程生命周期有效。

  3. 请求生命周期(Request lifecycle)

FPM‑SAPI生命周期(请求隔离)

请求到来 → 初始化PHP环境 → 执行用户代码 → 请求关闭阶段RSHUTDOWN → 释放请求资源 → Worker进程不退出,等待下一个请求

进程存活,请求级资源全部销毁

CLI普通脚本生命周期

脚本启动 → 执行全部代码 → 脚本结束,整个进程销毁退出

Swoole‑CLI常驻运行时

进程启动BOOT初始化(仅一次)→ 循环事件循环;每来一个请求新建协程;协程结束销毁协程资源;进程本身永不退出

  1. RINIT / RSHUTDOWN 请求初始化/请求关闭
  • RINIT:每一次请求到来执行;加载ini、超全局变量、GET/_GET/GET/_POST。FPM每次请求都会跑RINIT。
  • RSHUTDOWN:请求结束回调,做请求资源清理。

Hyperf/Swoole常驻模式:不会自动执行RINIT/RSHUTDOWN,需要框架自己模拟请求生命周期。

  1. GINIT / GSHUTDOWN 全局初始化/全局关闭
    进程启动执行一次,进程销毁执行一次。

常驻内存框架,业务初始化放在GINIT阶段。

二、Zend VM 虚拟机核心术语

  1. ZendVM 虚拟机
    PHP的执行引擎,不直接执行源码;执行编译后的Opcode字节码。
    工作流:PHP源码 → 编译为Opcode → ZendVM逐条解释执行。

  2. Opcode(操作码)
    编译生成的指令,类似汇编;ZEND_ADDZEND_ECHO等。OPcache缓存Opcode,跳过重复编译。

  3. OPcache
    字节码缓存扩展,把编译好的Opcode存共享内存;多个FPM Worker共享;避免每次请求编译源码消耗CPU。

  • opcache.validate_timestamps:开启会检测php文件修改;生产关闭,修改代码不自动生效。
  • opcache.revalidate_freq:文件检查周期。
  1. Zval 内核变量结构体
    PHP所有变量底层统一结构。
    成员:value(存储实际数据)、u1(type类型)、refcount__gc引用计数、is_ref__gc是否引用。

PHP一切变量都是zval:int string array object resource。

  1. refcount 引用计数
    根因:PHP内存管理基础。记录这个zval被多少变量引用;refcount降到0,内存释放。

缺陷:循环引用对象/数组,refcount无法自动回收,需要GC回收器

  1. GC 垃圾回收器(循环引用回收)
    专门处理$a=&$b; $b=&$a这种循环引用;达到gc_threshold阈值,触发GC扫描回收。
    代价:会消耗CPU,大对象多的时候会出现STW(stop‑the‑world)停顿。

  2. COW 写时复制 Copy‑On‑Write
    根因:节省内存。数组赋值$b = $a,不拷贝内存,refcount+1,共用同一份zval;只有发生修改时才真正复制内存
    坑:大数组传参,函数内部修改数组触发拷贝,内存瞬间飙升。

  3. 符号表(Symbol table)
    存储变量名到zval的映射;分全局符号表、局部函数符号表。

  • 全局符号表:$GLOBALS;FPM每次请求重置;Swoole常驻进程全局符号表进程级别,协程并发极易污染。
  1. EG(executor_globals)执行器全局
    Zend执行器上下文,保存调用栈、异常、错误处理、当前符号表。

  2. 调用栈(Call stack)
    函数/方法一层层调用形成栈帧;异常回溯、debug_backtrace读取调用栈。

  3. 栈帧(zend_execute_data)
    每一次函数调用生成一个栈帧;保存局部变量、返回地址。函数执行结束栈帧销毁。

三、变量、超全局、资源类型术语

  1. 超全局变量 $_GET $_POST $_COOKIE $_SESSION $_SERVER $_REQUEST $_FILES
    FPM:RINIT阶段每请求重新生成,请求隔离。

Swoole/Hyperf禁止直接使用超全局变量,多个协程共享进程全局,会发生数据错乱;框架封装Request对象从协程上下文拿数据。

  1. Resource资源类型
    内核外部句柄:mysql连接、文件句柄、socket句柄。
    资源是编号,不是真正指针;请求结束FPM自动回收释放;Swoole常驻不会自动回收,必须手动close。

  2. 静态变量 static $a
    函数内static变量:作用域是进程级别

  • FPM:同一个Worker多次请求之间static变量保留值;
  • Swoole:所有协程共享这个static变量,极易并发错乱。
  1. 全局变量 global $a
    存放在全局符号表,进程存活期间保留,常驻内存风险极高。

  2. 对象句柄(Object handle)
    PHP对象不直接拷贝;变量存对象编号,多个变量指向同一个对象实例。

四、错误、异常、运行时配置术语

  1. error_reporting 错误报告级别
    控制哪些级别错误会被抛出;E_ERROR、E_WARNING、E_NOTICE、E_DEPRECATED。

  2. display_errors
    是否把错误打印输出到页面;生产环境必须关闭。

  3. log_errors
    错误写入日志文件,线上开启。

  4. Exception 异常对象
    主动throw抛出,try‑catch捕获。

Error:致命错误,PHP7之后大部分致命错误转为Error异常,可以捕获。

  1. zend错误处理回调 set_error_handler、set_exception_handler
    接管错误、异常;框架用来统一记录日志。注意:部分致命错误无法捕获。

  2. php.ini
    PHP运行时配置文件。
    FPM:可以通过pool的php_value/php_admin_value覆盖;
    CLI/Swoole:启动时读取一份php.ini,运行时修改部分配置不生效。

  3. ini_set()
    运行时修改ini配置;部分配置受PHP_INI_*模式限制,运行时不可修改。

  • PHP_INI_ALL:代码可修改
  • PHP_INI_PERDIR:php.ini、.htaccess可改,代码不可改
  • PHP_INI_SYSTEM:仅php.ini可修改

五、两大SAPI运行时模型对比(核心考点)

模型1:FPM‑SAPI(请求隔离运行时)

  1. Worker进程常驻,但是每一次请求执行完整RINIT、RSHUTDOWN
  2. 请求结束,请求级符号表、局部变量、资源全部释放
  3. 但是进程级静态变量、全局变量在同一个Worker内跨请求保留
  4. 没有用户态协程,一个进程同一时刻只能处理1个请求
  5. 无内置连接池,数据库、redis连接属于请求资源,请求结束关闭

坑点:很多人误以为FPM每次请求销毁进程;只是销毁请求资源,进程本身复用。

模型2:Swoole‑CLI常驻内存运行时(Hyperf底层)

  1. 进程启动执行一次GINIT,永远不会自动执行RINIT/RSHUTDOWN
  2. 没有天然的请求隔离;全部请求/协程跑在同一个进程空间。
  3. 协程上下文模拟请求隔离;进程全局符号表、static静态变量对所有协程可见
  4. 对象、连接、数组不会请求结束自动清空,容易内存泄漏、协程污染。
  5. 需要框架手动管理资源:defer归还连接、协程退出清理上下文。

坑:直接使用GET/_GET/GET/_POST/global/static变量,会出现协程数据错乱。

六、扩展与钩子运行时术语

  1. PHP扩展(Extension)
    C语言编写,编译进PHP;分为内核扩展(pdo、curl)、第三方扩展(swoole、redis)。
    扩展可以修改ZendVM行为,注册函数、钩子。

  2. Zend钩子(Zend hook)
    内核回调钩子:opcode执行钩子、函数调用钩子;AOP、调试工具基于内核钩子实现。

  3. opcache预加载 opcache.preload
    PHP7.4+常驻内存预加载;进程启动把类一次性加载到内存,不用autoload;适合Swoole项目。

  4. autoload自动加载
    类找不到时触发__autoload/composer自动加载;FPM每次请求会触发;Swoole启动阶段全部加载完成,运行时几乎不再触发。

  5. __construct / __destruct 析构函数
    对象销毁时触发;FPM请求结束批量触发;Swoole常驻内存,对象不释放析构不会跑。

七、运行时故障坑点术语(高频)

  1. 请求级资源泄漏 vs 进程级内存泄漏
  • 请求级:单次请求内部内存大,RSHUTDOWN后释放,FPM不怕;
  • 进程级:static数组无限追加、全局变量不断堆数据;内存只涨不跌,FPM靠max_requests重启缓解;Swoole风险极高。
  1. 循环引用内存泄漏
    对象互相引用,refcount无法降为0,等待GC;GC不触发内存一直占用。

  2. 写时复制陷阱
    大数组传参,函数内部修改,触发COW复制,内存瞬间翻倍。

  3. 超全局变量污染(Swoole特有)
    直接使用$_GET $_POST,协程并发互相覆盖数据。

  4. 静态变量跨协程污染
    函数static变量,所有协程共享,并发请求数据错乱。

  5. RSHUTDOWN缺失
    Swoole没有原生RSHUTDOWN;资源不会自动回收,连接、文件句柄忘记关闭,持续泄漏。

  6. OPcache失效问题
    FPM开发环境忘记开启opcache.validate_timestamps,改代码看不到效果。

  7. STW停顿
    GC大规模回收循环引用对象,ZendVM暂停执行所有PHP代码,出现请求卡顿。

八、FPM运行时 vs Swoole常驻运行时对照表

运行时维度FPM‑SAPISwoole‑CLI常驻内存
RINIT/RSHUTDOWN每请求自动执行不会自动执行,框架模拟
全局符号表每请求重置进程全局,所有协程共享
static静态变量同Worker跨请求保留全部协程共享,高并发危险
超全局$_GET每请求重建,安全原生超全局不可直接使用
对象/资源回收RSHUTDOWN自动回收请求资源不会自动回收,需要手动释放
Opcode加载每请求autoload,OPcache缓存进程启动一次性全部加载
内存泄漏缓解手段pm.max_requests定期重启Worker无自动机制,代码层面管控

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询