SAPI接口
SAPI是一个用来帮助其他开发程序扩展web服务器功能的应用程序接口(api)。它将外部条件抽象, 为内部的PHP提供一套固定统一的接口, 使得PHP自身实现能够不受外部环境影响,保持一定的独立性。
PHP中常用的SAPI有cli(命令行模式,单进程)、php-fpm、CGI、Apache…
有点像策略模式,使用相同的接口,但是实现会略有不同。
看图很清楚就可以理解,sapi以上是使用php的各种方式mod_php,fastcgi,cli等等,sapi以下是php语言,我们使用php一切的开始就从sapi开始。
php的启动和终止
php开始阶段 (分两个阶段)
第一阶段:是在我们启动php-fpm,或者apache的时候是在所有请求到达之前进行的,且只进行一次。启动Apache或者php-fpm后,PHP解释程序也随之启动; PHP调用各个扩展(模块)的MINIT方法,从而使这些扩展切换到可用状态。看看php.ini文件里打开了哪些扩展吧; MINIT的意思是“模块初始化”。各个模块都定义了一组函数、类库等用以处理其他请求。 模块在这个阶段可以进行一些初始化工作,例如注册常量, 定义模块使用的类等等.
第二阶段:是在请求发生阶段,当一个页面请求发生时.则在每次请求之前都会进行初始化过程(RINIT请求开始).请求到达之后,SAPI层将控制权交给PHP层,PHP初始化本次请求执行脚本所需的环境变量,例如创建一个执行环境,包括保存php运行过程中变量名称和变量值内容的符号表. 以及当前所有的函数以及类等信息的符号表.例如是Session模块的RINIT,如果在php.ini中启用了Session 模块,那在调用该模块的RINIT时就会初始化$_SESSION变量,并将相关内容读入; 然后PHP会调用所有模块RINIT函数,即“请求初始化”。 在这个阶段各个模块也可以执行一些相关的操作, 模块的RINIT函数和MINIT函数类似 ,RINIT方法可以看作是一个准备过程,在程序执行之前就会自动执行。
php结束阶段(分两个阶段)
第一阶段:请求结束,请求处理完后就进入了结束阶段,PHP就会启动清理程序。它会按顺序调用各个模块的RSHUTDOWN方法。 RSHUTDOWN用以清除程序运行时产生的符号表,也就是对每个变量调用unset函数。
第二阶段:SAPI关闭,比如php-fpm销毁一个子进程。php调用每个扩展的MSHUTDOWN方法,这是各个模块最后一次释放内存的机会。
php的生命周期
单进程SAPI生命周期(CLI/CGI)
多进程SAPI声明周期(APACHE)
单进程图可以对映我们在命令行执行php脚本,MINT,RINT执行后执行我们的脚本代码,然后执行RSHUTDOWN,MSHUTDOWN就结束了。
多进程图可以对映php-fpm的方式,一个进程MINT后,循环执行RINT,RSHUTDOWN,循环处理很多请求直到该进程要销毁执行MINT,然后结束。
扩展
数据库长连接
在上面讲php结束阶段的时候我们知道php在执行RSHUTDOWN的时候会释放所有处理本次请求的资源,如申请的变量。那么理所当然的是我们打开的数据库连接句柄也会被释放,但是这只限于我们打开连接的时候使用的是短链接,看官方文档我们可知道如果你打开的是长连接,在请求处理完后php会收留在本次打开的连接(即使你主动关闭也不会关闭而被收留),在下次有打开相同连接的请求时php会把收留的句柄直接给出去,就免去了建立连接的过程效率更高。这个收留的域是MINT,MSHUTDOWN之间也就对应我们php-fpm的一个子进程存活期。
参考
https://www.cnblogs.com/wpjamer/articles/7107289.html
PHP 底层的运行机制与原理