PHP框架流程图
从整体来说,PHP可以细分为四个层次。最核心的,就是Zend引擎。其次就是和它搭配的PHP扩展(extensions)这个部分了。再来就是SAPI(Server Application Programming Interface,也就是服务端应用编程接口)这个部分,最后就是上层应用的部分(平时编写的PHP程序)。
四个部分的简单说明
Zend引擎:
Zend整体用纯C实现,是PHP的内核部分,它将PHP代码翻译(词法、语法解析等一系列编译过程)为可执行opcode(指令)的处理并实现相应的处理方法、
实现了基本的数据结构(如hashtable、oo)、内存分配及管理、提供了相应的api方法供外部调用,是一切的核心,所有的外围功能均围绕Zend实现。
Extensions:
围绕着Zend引擎,extensions通过组件式的方式提供各种基础服务,我们常见的各种内置函数(如array系列)、标准库等都是通过extension来实现,用户
也可以根据需要实现自己的extension以达到功能扩展、性能优化等目的。
SAPI:
Server Application Programming Interface,也就是服务端应用编程接口,SAPI通过一系列钩子函数,使得PHP可以和外围交互数据,通过SAPI成功
地将PHP本身和上层应用解耦隔离,PHP可以不再考虑如何针对不同应用进行兼容,而应用本身也可以针对自己的特点实现不同的处理方式。
上层应用:
平时编写的PHP程序,通过不同的sapi方式得到各种各样的应用模式,如通过webserver实现web应用、在命令行下以脚本方式运行等等。
PHP运行与加载
PHP提供很多种形式的接口,包括apache、apache2filter、apache2handler、caudium、cgi 、cgi-fcgi、cli、cli-server、continuity、embed、isapi、litespeed、milter、nsapi、phttpd pi3web、roxen、thttpd、tux和webjames。但是常用的只有5种形式,CLI/CGI(命令行)、Multiprocess(多进程)、Multithreaded(多线程)、FastCGI和Embedded(内嵌)。
无论使用哪种SAPI,在PHP执行脚本前后,都包含一系列事件:Module的init(MINT)和shutdown(MSHUTDOWN),Request 的init(RINT)和shutdown(RSHUTDOWN)。
第一阶段是PHP模块初始化阶段(MINIT),可以初始化扩展内部变量、分配资源和注册资源处理器,在整个PHP实例生命周期内,该过程只执行一次。
第二阶段是请求初始化阶段(RINIT),在模块初始化并激活后,会创建PHP运行环境,同时调用所有模块注册的RINT函数,调用每个扩展的请求初始化函数 ,设定特定的环境变量、分配资源或执行其他任务,如审核。
第三阶段(RSHUTDOWN),请求处理完成后,会调用PHP_RSHUTDOWN_FUNCTION进行回收,这是每个扩展的请求关闭函数,执行最后的清理工作。Zend引擎执行清理过程、垃圾收集、对之前的请求期间用到的每个变量执行unset。请求完成可能是执行到脚本完成,也可能是调用die()或exit()函数完成。
第四阶段(MSHUTDOWN),当PHP生命周期结束时候,PHP_MSHUTDOWN_FUNCTION对模块进行回收处理,这是每个扩展的模块关闭函数,用于关闭自己的内核子系统。
常见的SAPI运行模式
- CLI和CGI模式(单进程模式)
CLI和CGI都属于单进程模式,PHP的生命周期在一次请求中完成。也就是说每次执行PHP脚本,都会执行第二部分讲的四个INT和SHUTSDOWN事件。
- 多进程模式
该模式可以将PHP内置到Web Server中,PHP可以编译成Apache下的prefork MPM模式和APXS模块,当Apache启动后,会fork很多子进程,每个子进程拥有自
己独立的进程地址空间。在一个子进程中,PHP的生命周期是调用MINT启动后,执行多次请求(RINT/RSHUTDOWN),在Apache关闭或进程结束后,才会调用MS
HUTDOWN进行回收阶段。多进程模型中,每个子进程都是独立运行,没有代码和数据共享,因此一个子进程终止退出和重新生成,不会影响其他子进程的稳定。
- 多线程模式
Apache2的Worker MPM采用了多线程模型,在一个进程下创建多个线程,在同一个进程地址空间执行。
- FastCGI模式
在我们用的Nginx+PHP-FPM用的就是FastCGI模式,Fastcgi是一种特殊的CGI模式,是一种常驻进程类型的CGI,运行后可以Fork多个进程,不用花费时间
动态的Fork子进程,也不需要每次请求都调用MINT/MSHUTDOWN。PHP通过PHP-FPM来管理和调度FastCGI的进程池。Nginx和PHP-FPM通过本地的TCP Socket
和Unix Socket 进行通信。PHP-FPM进程管理器自身初始化,启动多个CGI解释器进程等待来自Nginx的请求。当客户端请求达到PHP-FPM,管理器选择到一个
CGI进程进行处理,Nginx将CGI环境变量和标准输入发送到一个PHP-CGI子进程。PHP-CGI子进程处理完成后,将标准输出和错误信息返回给Nginx,当
PHP-CGI子进程关闭连接时,请求处理完成。PHP-CGI子进程等待着下一个连接。可以想象CGI的系统开销有多大。每一个Web 请求PHP都必须重新解析
php.ini、载入全部扩展并初始化全部数据结构。使用FastCGI,所有这些都只在进程启动时发生一次。另外,对于数据库和Memcache的持续连接可以工作。
- 嵌入式
Embed SAPI是一种特殊的SAPI,允许在C/C++语言中调用PHP提供的函数。这种SAPI和CLI模式一样,按照
Module Init => Request Init => Request => Request Shutdown => Module Shutdown的模式运行。
Embed SAPI可以调用PHP丰富的类库,也可以实现高级玩法,比如可以查看PHP的OPCODE(PHP执行的中间码,Zend引擎的指令,由PHP代码生成)。