PHP 怎么PHP 启动流程

wen PHP项目 3

本文目录导读:

PHP 怎么PHP 启动流程

  1. PHP 的模块化启动模式
  2. PHP 启动的核心流程(以 Apache mod_php 为例)
  3. 经典扩展初始化宏(C 语言级别)
  4. 详细的 CLI 启动流程(单次运行)
  5. 关键优化机制
  6. 流程图(简洁版)
  7. 关键要点总结

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 引擎。
    • 加载内置扩展(如 datepdombstring 等)。
    • 分配全局资源(如内存管理器、错误处理栈)。

阶段 2:请求初始化(收到 HTTP 请求后)

  • 调用 PHP_RINIT_FUNCTION(Request Init):
    • 创建新的请求上下文
    • 初始化全局变量($_SERVER$_REQUEST 等)。
    • 重置输出缓冲机制。
    • 加载用户配置(如 .htaccess 中的 php_value)。

阶段 3:脚本执行

  1. 词法分析:PHP 代码 → tokens(zlex)。
  2. 语法分析:tokens → 抽象语法树(AST)。
  3. 编译:AST → opcode(中间指令,类似字节码)。
  4. 执行: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 时可以选择不销毁,复用于下一个请求。
  • 懒加载

    类和函数定义仅在首次调用时编译(避免每次请求都加载所有代码)。


流程图(简洁版)

服务器启动(Apache)
 └─ 加载 mod_php
     └─ PHP_MINIT (全局 ini, 扩展注册)
         │
请求到达
 ├─ PHP_RINIT (请求级初始化, 全局变量)
 ├─ 编译脚本为 opcode (若 OPcache 未命中)
 ├─ Zend 虚拟机执行 opcode
 └─ PHP_RSHUTDOWN (清理, 输出结果)
     │
下一个请求 → 重复 RINIT → 执行 → RSHUTDOWN

关键要点总结

概念 说明
MINIT 只运行一次,用于全局静态资源初始化。
RINIT 每个请求运行一次,用于隔离请求数据。
RSHUTDOWN 清理请求资源,释放内存。
MSHUTDOWN 进程退出前运行,释放全局资源。
OPcache 避免重复编译,节省 CPU。

如果你需要我绘制更详细的调用栈图或解释某个特定 SAPI(如 FPM)的启动差异,可以直接告诉我。

抱歉,评论功能暂时关闭!