PHP生命周期
在各个服务器抽象层质检遵守着相同的约定,称之为SAPI接口,每个SAPI接口实现都是一个_sapi_module_struct结构体变量。在PHP的源码中,当需要调用服务器相关信息是时,都需要通过SAPI接口中对应的方法调用实现。 在PHP生命周期的各个阶段,一些与服务相关的操作也会通过SAPI接口实现。这些内置实现的物理位置在PHP源码的SAPI目录。
SAPI(Server Application Programming Interface)指的是PHP具体应用的编程接口,就像PC一样,无论安装哪些操作系统,只要满足了PC的接口规范,都可以在PC上正常运行,PHP脚本执行有多种方式,通过web服务器(Apache、Nginx),或者直接在命令行下,也可以嵌入到其他的程序中。
脚本执行的开始都是以SPAI接口实现开始的。只是不同的SAPI接口实现会完成它们特定的工作,例如,Apache的mod_php SAPI实现需要初始化Apache获取的一些信息,在输出内容时将内容返回给Apache,其他的SAPI实现也类似。
1、开始和结束:
PHP开始执行后会经过两个主要的阶段:处理请求之前的开始阶段和请求之后的结束阶段。开始阶段有两个过程:过程一是模块初始化阶段(MINIT),在整个SAPI生命周期内(例如Apache启动后的整个生命中周期内或者命令行程序整个执行过程中),该过程仅执行一次;过程二是模块激活阶段(RINIT),该过程发生在请求阶段,例如通过url请求某个页面,则在每次请求之前都会进行模块激活。
请求到达之后PHP初始化执行脚本的基本环境,例如创建一个执行环境等。然后PHP会调用所有模块的RINIT函数,在这个阶段各个模块也会执行一些相关的操作。
请求处理完成后就进入了结束阶段,一般脚本执行到末尾或者通过调用exit()或die()函数,PHP都将进入结束阶段。同样包含两个环节:在请求结束后停用模块(RSHUTDOWN,对应RINIT) 和 在SAPI生命周期结束是关闭模块(MSHUDOWN,对应MINIT)。
2、单进程SAPI生命周期:(模块初始化、SAPI初始化、处理PHP请求、模块关闭、SAPI关闭)
CLI/CGI模式的PHP属于单进程的SAPI模式,这类的请求在处理一次请求后就关闭。
①启动,在调用各个模块的模块初始化前,会有一个初始化的过程:
初始化若干全局变量(大多设置为null),初始化若干常量(PHP自己的一些常量,要么是硬编码在程序中,比如PHP_VERSION,要么写在配置头文件中),初始化Zend引擎和核心组件,解析php.ini(php_ini_config函数的作用是读取php.ini文件,设置配置参数,加载zend扩展并注册PHP扩展函数),全局操作函数初始化,初始化静态构建的模块和共享模块,禁用函数和类
②PHP调用php_request_startup做请求初始化操作,除了调用每个模块请求初始化函数外,还有一些其他操作:激活zend引擎,激活SAPI,环境初始化,模块请求初始化
③脚本运行:php_execute_script函数包含了脚本运行的全部过程。当一个PHP文件需要解析执行是,它可能需要执行前置执行文件、当前需要执行的文件、后置执行文件三个文件。对于需要解析执行的文件,通过zend_compile_file做词法分析、语法分析和中间代码生成操作,返回此文件的所有中间代码。
④请求关闭:PHP关闭请求的过程是一个若干个关闭操作的集合,这个集合存在于php_request_shutdown函数中
⑤结束:flush(sapi_flush将最后的内容刷新出去),关闭Zend引擎(zend_shutdown)
3、多进程SAPI生命周期
通常PHP是编译为Apache的一个模块来处理PHP请求的。Apache一般会采用多进程模式,Apache启动后会fork出多个子进程,每个进程的内存空间独立、都会经过开始—结束环节,每个进程开始阶段只在fork出来以后进行,在整个进程的生命周期内可能会处理多个请求。之后在Apache关闭或者进程被结束之后才会进行关闭阶段,在这两个阶段之间会随着每个请求重复请求开始-请求关闭的环节。