小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
运行模式
PHP 常见的运行模式有如下几种:
-
CGI:(Common Gateway Interface,通用网关接口),Fork-And-Execute 模式
-
FastCGI:(Fast Common Gateway Interface),是 CGI 的改进版,分为管理进程和工作进程。
-
CLI:(Command Line Interface,命令行运行),当我们在终端敲入
php这个命令的时候,它使用的就是 CLI。 -
Web 模块模式:Apache 等 Web 服务器运行的模式。
无论哪种运行模式,PHP 工作原理都是一样的,作为一种 SAPI 运行。
那么,什么是 SAPI 呢?
SAPI 全称是 Server Application Programming Interface,即服务器应用编程接口,实质上就是定义了一个统一的接口。
在 PHP 应用中,SAPI 是应用层(比如 Apache、Nginx、CLI 等)和 PHP 交互数据的入口。而就是 SAPI 这个入口,使得 PHP 和其上面的应用层解耦合了。
CGI、FastCGI、CLI 等都可以称为 SAPI。
生命周期
我们再来看看生命周期的概念。
生命周期,我们可以把它理解为一个东西从出生到死亡,这个过程就叫做生命周期。
在程序世界中也有其它名词对应着生命周期,比如执行过程,PHP 生命周期可以简单的理解为 PHP 从开始执行到结束执行的过程。
以 CGI 为例,我们来看一下一条请求的生命周期(不同的运行模式生命周期有些差别):
当一条请求到来时,首先会在服务器上 Fork 一个 CGI 进程,该进程开始处理请求,处理完后返回响应数据,最后停掉 CGI 进程。

PHP 生命周期
PHP 生命周期中关键四个调用:MINT(模块初始化) -> RINT(请求初始化) -> RSHUTDOWN(请求关闭) -> MSHOTDOWN(模块关闭)
PHP 的整个生命周期可以被划分为以下几个阶段:模块初始化阶段、请求初始化阶段、脚本执行阶段、请求关闭阶段、模块关闭阶段。
一个 PHP 实例,无论通过 HTTP 请求调用的,还是从命令行启动的,都会依次进行 MINIT、RINIT、RSHUTDOWN、MSHUTDOWN 四个过程,当然之间还会执行脚本自己的逻辑。那么两种 INIT 和两种 SHUTDOWN 各会执行多少次、各自的执行频率有多少呢?这取决于 PHP 是用什么 SAPI 与宿主通信的。比如在 CLI 模式下,每次执行一个脚本都会完整地经历这些阶段,而在 FastCGI 模式下则只会在启动时执行一次 MINIT。
模块初始化阶段(MINIT)
-
启动 PHP 输出、初始化垃圾收集器
-
启动 Zend 引擎,注册 Zend 核心扩展、Zend 标准常量
-
解析
php.ini,映射php.ini相关配置 -
注册静态、动态编译的扩展
-
回调各扩展定义的 module startup 钩子函数。
用一句话来说,就是初始化类、常量、扩展等 PHP 所用到的资源。
请求初始化阶段(RINIT)
PHP 初始化脚本执行的基本环境,SAPI 将控制权交给 PHP,激活 Zend 引擎,初始化执行器。
对于 PHP-FPM 而言,是在 worker 进程中 accept 一个请求并读取、解析完请求数据后的一个阶段。
PHP 脚本执行
Zend 引擎接管控制权,将 PHP 脚本编译成 Opcodes,并顺序执行。
请求结束阶段(RSHUTDOWN)
PHP 脚本执行完之后进入请求结束阶段,PHP 启动清理程序,这个阶段,将 flush 输出内容,发送 HTTP 响应内容,关闭 PHP 执行器等。
模块关闭阶段(MSHUTDOWN)
这个阶段主要是进行资源的清理、PHP 各模块的关闭操作,同时,将回调各扩展的 module shutdown 钩子函数,这是发生在所有请求都已经结束之后,例如关闭 FPM 的操作。
FastCGI 模式下 PHP 的生命周期

总结
- 什么是 SAPI?
- PHP 引擎对外的一个统一接口,使得 PHP 可以和外部程序进行交互。
-
PHP 运行模式有几种?
-
CGI 模式;
-
FastCGI 模式;
-
CLI 模式;
-
Web 模块模式;
-
CLI 模式下的生命周期和 FastCGI 模式下的生命周期有何不同?
- PHP 的整个生命周期可以被划分为以下几个阶段:模块初始化阶段、请求初始化阶段、脚本执行阶段、请求关闭阶段、模块关闭阶段。根据不同的 SAPI 的实现,各阶段的执行情况会略有差异。比如在 CLI 模式下,每次执行一个脚本都会完整地经历这些阶段,而在 FastCGI 模式下则只会在启动时执行一次模块初始化。