本文目录导读:

PHP 的启动流程可以分为 几个关键阶段,从服务器(如 Apache、Nginx、CLI)接收到请求开始,到 PHP 引擎完成初始化、执行脚本并返回响应,下面是详细的步骤解析:
PHP 的模块化启动模式
在深入了解流程前,先明确 PHP 运行时的两种模式:
| 运行模式 | 说明 |
|---|---|
| 模块模式(如 Apache mod_php) | PHP 作为 Web 服务器模块,随服务器进程启动,仅在首次请求时初始化。 |
| CGI/FastCGI(如 Nginx + FPM) | 每个请求 → 创建独立 PHP 进程(或复用进程池),处理完请求后保持进程存活。 |
PHP 启动的核心流程(以 Apache mod_php 为例)
阶段 1:模块加载(服务器启动时)
- Apache 加载
mod_php模块。 - 调用
PHP_MINIT_FUNCTION(Module Init):- 解析
php.ini。 - 注册 Zend 引擎。
- 加载内置扩展(如
date、pdo、mbstring等)。 - 分配全局资源(如内存管理器、错误处理栈)。
- 解析
阶段 2:请求初始化(收到 HTTP 请求后)
- 调用
PHP_RINIT_FUNCTION(Request Init):- 创建新的请求上下文。
- 初始化全局变量(
$_SERVER、$_REQUEST等)。 - 重置输出缓冲机制。
- 加载用户配置(如
.htaccess中的php_value)。
阶段 3:脚本执行
- 词法分析:PHP 代码 → tokens(
zlex)。 - 语法分析:tokens → 抽象语法树(AST)。
- 编译:AST → opcode(中间指令,类似字节码)。
- 执行:Zend 虚拟机逐条执行 opcode。
- 遇到函数/类定义时延迟编译。
- 遇到
include/require→ 插入新的文件,递归编译执行。
阶段 4:请求结束
- 调用
PHP_RSHUTDOWN_FUNCTION(Request Shutdown):- 清空请求级变量。
- 关闭打开的数据库连接(未持久化的)。
- 执行
register_shutdown_function()注册的回调。 - 输出缓冲区内容(如
ob_flush()后发送到客户端)。 - 销毁请求上下文。
阶段 5:进程/线程的持续运行
- 如果是
mod_php的 Worker 模式:进程不退出,等待下一个请求 → 返回阶段 2。 - 如果是 FPM:请求处理完后,Worker 进程继续监听新请求。
经典扩展初始化宏(C 语言级别)
PHP 扩展通过以下宏标记其生命周期:
// MINIT: 模块加载时调用一次(如注册类常量、ini 条目)
PHP_MINIT_FUNCTION(my_ext) { ... }
// RINIT: 每个请求开始时调用(如分配请求级缓存)
PHP_RINIT_FUNCTION(my_ext) { ... }
// RSHUTDOWN: 每个请求结束时调用
PHP_RSHUTDOWN_FUNCTION(my_ext) { ... }
// MSHUTDOWN: 模块卸载时调用(Apache 停止或 FastCGI 进程关闭)
PHP_MSHUTDOWN_FUNCTION(my_ext) { ... }
详细的 CLI 启动流程(单次运行)
当你执行 php -f script.php 时:
加载 PHP 二进制文件
2. 调用 sapi_startup()
├── 初始化 SAPI 全局变量(如 CLI 模式)
3. 调用 php_module_startup()
├── 解析 php.ini
├── PHP_MINIT (所有注册扩展)
└── 设置 zend 引擎
4. 调用 php_request_startup()
├── PHP_RINIT (扩展)
├── 初始化全局变量
├── 设置输出缓冲
5. 编译、执行 script.php(opcode 编译 → 执行)
6. 执行完毕,调用 php_request_shutdown()
├── PHP_RSHUTDOWN (扩展)
├── 刷新输出缓冲
├── 释放请求级内存
7. 调用 php_module_shutdown()
├── PHP_MSHUTDOWN (扩展)
├── 释放全局资源
8. 退出进程,返回 0
关键优化机制
- opcode 缓存(如 OPcache):
- 编译后的 opcode 被缓存到共享内存。
- 后续请求直接复用,跳过编译阶段(阶段 3 中的词法/语法/编译,只剩执行)。
- 持久连接:
- 数据库 PDO/MySQL 连接在
RSHUTDOWN时可以选择不销毁,复用于下一个请求。
- 数据库 PDO/MySQL 连接在
- 懒加载:
类和函数定义仅在首次调用时编译(避免每次请求都加载所有代码)。
流程图(简洁版)
服务器启动(Apache)
└─ 加载 mod_php
└─ PHP_MINIT (全局 ini, 扩展注册)
│
请求到达
├─ PHP_RINIT (请求级初始化, 全局变量)
├─ 编译脚本为 opcode (若 OPcache 未命中)
├─ Zend 虚拟机执行 opcode
└─ PHP_RSHUTDOWN (清理, 输出结果)
│
下一个请求 → 重复 RINIT → 执行 → RSHUTDOWN
关键要点总结
| 概念 | 说明 |
|---|---|
| MINIT | 只运行一次,用于全局静态资源初始化。 |
| RINIT | 每个请求运行一次,用于隔离请求数据。 |
| RSHUTDOWN | 清理请求资源,释放内存。 |
| MSHUTDOWN | 进程退出前运行,释放全局资源。 |
| OPcache | 避免重复编译,节省 CPU。 |
如果你需要我绘制更详细的调用栈图或解释某个特定 SAPI(如 FPM)的启动差异,可以直接告诉我。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播