一切的开始: SAPI接口
通常我们编写PHP Web程序都是通过Apache或者Nginx这类Web服务器来测试脚本. 或者在命令行下通过php程序来执行PHP脚本. 执行完成脚本后,服务器应答,浏览器显示应答信息,或者在命令结束后在标准输出显示内容. 我们很少关心PHP解释器在哪里. 虽然通过Web服务器和命令行程序执行 脚本看起来很不一样. 实际上她们的工作是一样的. 命令行程序和Web程序类似, 命令行参数传递给要执行的脚本,相当于通过url 请求一个php页面. 脚本戳里完成后返回响应结果,只不过命令行响应的结果是显示在终端上. 脚本执行的开始都是通过SAPI接口 进行的. 下一节将对SAPI进行更为深入的介绍.
开始和结束
PHP通过SAPI开始以后会经过两个主要的阶段. 处理请求之前的开始阶段和请求之后的结束阶段. 开始阶段有两个过程, 第一个是在 整个SAPI生命周期内(例如Apache启动以后的整个生命周期内或者命令行程序整个执行过程中)的开始阶段(MINIT),该阶段只进行一次. 第二个过程 发生在请求阶段,例如通过url请求某个页面.则在每次请求之前都会进行初始化过程(RINIT请求开始). 例如PHP注册了一些PHP模块,则在MINIT阶段会回调所有模块的MINIT函数. 模块在这个阶段可以进行一些初始化工作,例如注册常量, 定义 模块使用的类等等. 一般的模块回调函数
PHP_MINIT_FUNCTION(myphpextension) { // 注册常量或者类等初始化操作 return SUCCESS; }
请求到达之后PHP初始化执行脚本的基本环境,例如创建一个执行环境,包括保存php运行过程中变量名称和变量值内容的符号表. 以及当前所有 的函数以及类等信息的符号表. 然后PHP会调用所有模块RINIT函数, 在这个阶段各个模块也可以执行一些相关的操作, 模块的RINIT函数和MINIT函数类似
PHP_RINIT_FUNCTION(myphpextension) { // 例如记录请求开始时间 // 随后在请求结束的时候记录结束时间.这样我们就能够记录下处理请求所花费的时间了 return SUCCESS; }
请求处理完后就进入了结束阶段, 一般脚本执行到末尾或者通过调用exit()或者die()函数,php都将进入结束阶段. 和开始阶段对应,结束阶段也分为 两个环节,一个在请求结束后(RSHUWDOWN),一个在SAPI生命周期结束时(MSHUTDOWN).
PHP_RSHUTDOWN_FUNCTION(myphpextension) { // 例如记录请求结束时间, 并把相应的信息写入到日至文件中. return SUCCESS; }
想要了解扩展开发的相关内容,请参考第十三章 扩展开发
单进程SAPI生命周期
CLI/CGI模式的PHP属于单进程的SAPI模式. 这类的请求只处理一次请求就关闭. 也就是只会经过如下几个环节 开始 – 请求开始 – 请求关闭 – 结束 SAPI 接口就完成了其生命周期
多进程SAPI生命周期
通常PHP是编译为一个apache的模块来处理PHP请求的. 通常Apache会采用多进程模式, apache启动后fork出多个子进程, 每个进程的内存空间独立, 每个子进程都会经过开始和结束环节,不过每个进程的开始阶段只在进程fork出来以来后进行, 在整个进程的生命周期内可能会处理多个请求. 只有 在Apache关闭或者进程被结束之后才会进行关闭阶段,在这两个阶段之间会随着每个请求重复请求开始-请求关闭的环节.
多线程的SAPI生命周期
而在多线程模式下和多进程中的某个进程类似,不同的是在整个进程的生命周期内会并行的重复着 请求开始-请求关闭的环节
Zend引擎
Zend引擎作为PHP实现的核心,提供了语言实现上的基础设施.例如: PHP的语法实现, 脚本的编译运行环境, 扩展机制以及内存管理等, 可以说Zend引擎是PHP的核心, 当然这里的PHP指的是官方的PHP实现(除了官方的实现,目前比较知名的有facebook的hiphop实现,不过到目前为止,PHP还没有一个标准的语言规范), 而PHP则提供了请求处理和其他Web服务器的接口(SAPI).
参考文献
Extending and Embedding PHP
作者:TIPI团队