王帅:深入PHP内核(二)——SAPI探究(精辟)
SAPI是Server Application Programming Interface(服务器应用编程接口)的缩写。PHP通过SAPI提供了一组接口,供应用和PHP内核之间进行数据交互。
简单的讲,就像函数的输入和输出一样,我们通过Linux命令行执行一段PHP代码,本质是Linux的Shell通过PHP的SAPI传入一组参数,Zend引擎执行后,返回给shell,由shell显示出来的过程。同样的,通过Apache调用PHP,通过Web服务器给SAPI传入数据,Zend引擎执行后,返回给Apache,由Apache显示在页面上。
图1. 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(内嵌)。
PHP提供了一个函数查看当前SAPI接口类型:
- string php_sapi_name ( void )
PHP的运行和加载
无论使用哪种SAPI,在PHP执行脚本前后,都包含一系列事件:Module的Init(MINT)和Shutdown(MSHUTDOWN),Request 的Init(RINT)和Shutdown(RSHUTDOWN)。 第一阶段是PHP模块初始化阶段(MINT),可以初始化扩展内部变量、分配资源和注册资源处理器,在整个PHP实例生命周期内,该过程只执行一次。
什么是PHP模块?通过上面的PHP架构图,在PHP中可以使用get_loaded_extensions 函数来查看所有编译并加载的模块/扩展,相当于CLI模式下的php -m。
以PHP的Memcached扩展源代码为例:
- PHP_MINIT_FUNCTION(memcached) {
- zend_class_entry ce;
- memcpy(&memcached_object_handlers,zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- memcached_object_handlers.clone_obj = NULL; /* 执行了一些类似的初始化操作 */
- return SUCCESS;
- }
第二阶段是请求初始化阶段(RINT),在模块初始化并激活后,会创建PHP运行环境,同时调用所有模块注册的RINT函数,调用每个扩展的请求初始化函数 ,设定特定的环境变量、分配资源或执行其他任务,如审核。
- PHP_RINIT_FUNCTION(memcached) {
- /* 执行一些关于请求的初始化 */
- return SUCCESS;
- }
第三阶段,请求处理完成后,会调用PHP_RSHUTDOWN_FUNCTION进行回收,这是每个扩展的请求关闭函数,执行最后的清理工作。Zend引擎执行清理过程、垃圾收集、对之前的请求期间用到的每个变量执行unset。请求完成可能是执行到脚本完成,也可能是调用die()或exit()函数完成
第四阶段,当PHP生命周期结束时候,PHP_MSHUTDOWN_FUNCTION对模块进行回收处理,这是每个扩展的模块关闭函数,用于关闭自己的内核子系统。
- PHP_MSHUTDOWN_FUNCTION(memcached) { /* 执行关于模块的销毁工作 */ UNREGISTER_INI_ENTRIES(); return SUCCESS; }
常见的运行模式
常见的SAPI模式有五种:
- CLI和CGI模式(单进程模式)
- 多进程模式
- 多线程模式
- FastCGI模式
- 嵌入式
1. CLI/CGI模式
CLI和CGI都属于单进程模式,PHP的生命周期在一次请求中完成。也就是说每次执行PHP脚本,都会执行第二部分讲的四个INT和Shutdown事件。
图2. CGI/CLI生命周期
2. 多进程模式(Multiprocess)
多进程模式可以将PHP内置到Web Server中,PHP可以编译成Apache下的prefork MPM模式和APXS模块,当Apache启动后,会fork很多子进程,每个子进程拥有自己独立的进程地址空间。
图3. 多进程模式生命周期
在一个子进程中,PHP的生命周期是调用MINT启动后,执行多次请求(RINT/RSHUTDOWN),在Apache关闭或进程结束后,才会调用MSHUTDOWN进行回收阶段。
图4. 多进程的生命周期
多进程模型中,每个子进程都是独立运行,没有代码和数据共享,因此一个子进程终止退出和重新生成,不会影响其他子进程的稳定。
3. 多线程模式(Multithreaded)
Apache2的Worker MPM采用了多线程模型,在一个进程下创建多个线程,在同一个进程地址空间执行。
图5. 多线程生命周期
4. FastCGI模式
在我们用的Nginx+PHP-FPM用的就是FastCGI模式,Fastcgi是一种特殊的CGI模式,是一种常驻进程类型的CGI,运行后可以Fork多个进程,不用花费时间动态的Fork子进程,也不需要每次请求都调用MINT/MSHUTDOWN。PHP通过PHP-FPM来管理和调度FastCGI的进程池。Nginx和PHP-FPM通过本地的TCP Socket和Unix Socket 进行通信。
图6. FastCGI模式生命周期
PHP-FPM进程管理器自身初始化,启动多个CGI解释器进程等待来自Nginx的请求。当客户端请求达到PHP-FPM,管理器选择到一个CGI进程进行处理,Nginx将CGI环境变量和标准输入发送到一个PHP-CIG子进程。PHP-CGI子进程处理完成后,将标准输出和错误信息返回给Nginx,当PHP-CGI子进程关闭连接时,请求处理完成。PHP-CGI子进程等待着下一个连接。
可以想象CGI的系统开销有多大。每一个Web 请求PHP都必须重新解析php.ini、载入全部扩展并始化全部数据结构。使用FastCGI,所有这些都只在进程启动时发生一次。另外,对于数据库和Memcache的持续连接可以工作。
5. 内嵌模式(Embedded)
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代码生成)。
详细请见: http://www.laruence.com/2008/09/23/539.html
SAPI的运行机制
我们以CGI为例,看一下SAPI的运行机制。
- static sapi_module_struct cgi_sapi_module = {
- "cgi-fcgi", /* 输出给php_info()使用 */ "CGI/FastCGI", /* pretty name */
- php_cgi_startup, /* startup 当SAPI初始化时,首先会调用该函数 */
- php_module_shutdown_wrapper, /* shutdown 关闭函数包装器,它用来释放所有的SAPI的数据结构、内存等,调用php_module_shutdown */
- sapi_cgi_activate, /* activate 此函数会在每个请求开始时调用,它会做初始化,资源分配 */
- sapi_cgi_deactivate, /* deactivate 此函数会在每个请求结束时调用,它用来确保所有的数据都得到释放 */
- sapi_cgi_ub_write, /* unbuffered write 不缓存的写操作(unbuffered write),它是用来向SAPI外部输出数据 */
- sapi_cgi_flush, /* flush 刷新输出,在CLI模式下通过使用C语言的库函数fflush实现*/ NULL, /* get uid */
- sapi_cgi_getenv, /* getenv 根据name查找环境变量 */
- php_error, /* error handler 注册错误处理函数 */
- NULL, /* header handler PHP调用header()时候被调用 */
- sapi_cgi_send_headers, /* send headers handler 发送头部信息*/
- NULL, /* send header handler 发送一个单独的头部信息 */
- sapi_cgi_read_post, /* read POST data 当请求的方法是POST时,程序获取POST数据,写入$_POST数组 */
- sapi_cgi_read_cookies, /* read Cookies 获取Cookie值 */
- sapi_cgi_register_variables, /* register server variables 给$_SERVER添加环境变量 */
- sapi_cgi_log_message, /* Log message 输出错误信息 */
- NULL, /* Get request time */
- NULL, /* Child terminate */
- STANDARD_SAPI_MODULE_PROPERTIES
- };
由上面代码可见,PHP的SAPI像是面向对象中基类,SAPI.h和SAPI.c包含的函数是抽象基类的声明和定义,各个服务器用的SAPI模式,则是继承了这个基类,并重新定义基类方法的子类。
总结
PHP的SAPI是Zend引擎提供的一组标准交互接口,通过注册初始化、析构、输入、输出等接口,我们可以将应用程序运行在Zend引擎上,也可以把PHP嵌入到类似Apache的Web Server中。PHP常见的SAPI模式有五种,CGI/CLI模式、多进程模式、多线程模式、FastCGI模式和内嵌模式。
了解PHP的SAPI机制意义重大,帮助我们理解PHP的生命周期,并了解如何更好的通过C/C++为PHP编写扩展,并在生命周期中找到提高系统性能的方式。
关于作者:王帅,腾讯企业QQ SaaS团队Leader。
来源:http://www.csdn.net/article/2014-09-26/2821885-exploring-of-the-php-2
王帅:深入PHP内核(二)——SAPI探究(精辟)相关推荐
- 【问底】王帅:深入PHP内核(二)——SAPI探究
SAPI是Server Application Programming Interface(服务器应用编程接口)的缩写.PHP通过SAPI提供了一组接口,供应用和PHP内核之间进行数据交互. 简单的讲 ...
- 王帅:深入PHP内核(二)——SAPI探究
原文地址:http://www.csdn.net/article/2014-09-26/2821885-exploring-of-the-php-2 SAPI是Server Application P ...
- 凸透镜成像动画可拖动_光学实验二:探究凸透镜成像规律
[实验名称] 探究凸透镜成像的规律 [实验目的] 透镜凸透镜成像规律.像与物的大小关系.物距变化成像规律变化.像的虚实. [实验器材] 凸透镜.光具座.蜡烛.光屏.火柴等. [实验装置] [实验步骤] ...
- SpringBoot学习(二)探究Springboot启动机制
引言: SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏.所以这次博主就跟你们一起探究一下SpringBoot的启动原 ...
- PHP内核之SAPI:Apache2 SAPI分析
1.首先概念普及: SAPI: Server abstraction API,它提供了一个接口,使得PHP可以和其他应用进行交互数据,具体点说是提供了一个和外部通信的接口.常见的:给apache的mo ...
- webGIS学习(二)探究本质,WebGIS前端地图显示之地图比例尺换算原理 发布于 3 年前 作者 lzxue 7473 次浏览 来自 技术 1.没有豆浆机怎么办? 喝豆浆是我们早晨中基本
1.没有豆浆机怎么办? 喝豆浆是我们早晨中基本必备的一环,油条豆浆,其乐融融.如果我问大家豆浆是怎么来的,五谷不分的人会说是用钱买的,了解有黄豆这会事的人会说是用豆浆机把黄豆磨出来的.如果我们再倒退十 ...
- 精仿互站模板 友价源码商城T5内核二次开发运营版
精仿互站模板,友价T5内核1:1大型源码虚拟物品交易网站T5仿互站友价仿互站全新运营版,去住所有后门并且加强了防护(各种软件已经检测) 运行环境: 支持: IIS.apache.nginx PHP:p ...
- SYN-Flood遭遇战——Linux内核SYN-Cookie实现探究
SYN Flood好使啊,成本低廉,简单暴力,杀伤力强,更重要的是:无解,一打一个准!这种攻击充分利用了TCP协议的弱点,可以很轻易将你的网络打趴下.如果监控和应急不到位的话,那就等着被用户骂吧. 虽 ...
- Maccms苹果cmsV10内核二开听书网有声小说在线听书听书模板+源码+火车头采集+后台API自动采集
最新苹果cms懒人听书+精仿芒果Tv超美听书模板小说源码程序自动更新 源码介绍: 苹果cms精仿芒果Tv超美听书模板源码 手机版修改logo,ting_wap/images/logo.png 电脑版修 ...
最新文章
- 1.17 项目实例:模仿斗地主洗牌发牌小游戏
- 什么叫计算机网络阻塞,计算机网络中的“线端阻塞”释义
- 三维重建:***三维模型的网格细化
- ansible中yaml语法应用
- [html] 说说你对网格布局的理解
- 课外知识----浏览器存储技术
- windows10下Kafka环境搭建
- EasyUI remote ajax方式提交验证
- 【汇编语言与计算机系统结构笔记19】虚存概念初步,MIPS内存管理
- 股票python量化交易014-计算收益率
- Android 串口蓝牙通信开发Java版本
- 扣血抖动和FPS显示
- SSL协议密钥交换过程理解
- 【NX2023/1847】UG软件安装详细指南教程
- jq身份证号验证(详细)
- html创建关联程序,如何在控制面板中创建电子邮件默认程序关联
- JAVA面试算法小记
- 【阅读理解】深入移动端的适配-详尽篇
- Google搜索引擎的奥秘
- 使用 MoveIt 控制自己的真实机械臂【4】——了解 MoveIt 的轨迹规划实现机制
热门文章
- C 读写php,C语言读取文件所有内容
- android eng 模式,android 4.0 编译模式 eng - user 时遇到的有关问题
- 3.TF-IDF算法介绍、应用、NLTK实现TF-IDF算法、Sklearn实现TF-IDF算法、算法的不足、算法改进
- 2.非关系型数据库(Nosql)之mongodb:mongodb显示所有数据库,使用数据库,集合创建(显示和隐式创建),集合查询,初步数据的增删改查,分页
- java中文字符怎么保证出现正确_JAVA中文字符编码问题详解
- 使用pycaffe读取caffemodel参数(保存到txt文件)
- Dropout_layer.cpp(防止过拟合)
- C++中c_str的用法
- 深入浅出:5G和HTTP
- java自学之路-day17