PHP内核探索:再次探讨SAPI

很多操作都是通过SAPI接口实现
服务器君一共花费了281.360 ms进行了6次数据库查询,努力地为您提供了这个页面。
试试阅读模式?希望听取您的建议

在PHP的生命周期的各个阶段,一些与服务相关的操作都是通过SAPI接口实现。 这些内置实现的物理位置在PHP源码的SAPI目录。这个目录存放了PHP对各个服务器抽象层的代码, 例如命令行程序的实现,Apache的mod_php模块实现以及fastcgi的实现等等。

在各个服务器抽象层之间遵守着相同的约定,这里我们称之为SAPI接口。 每个SAPI实现都是一个_sapi_module_struct结构体变量。(SAPI接口)。 在PHP的源码中,当需要调用服务器相关信息时,全部通过SAPI接口中对应方法调用实现, 而这对应的方法在各个服务器抽象层实现时都会有各自的实现。

下面是为SAPI的简单示意图:

以cgi模式和apache2服务器为例,它们的启动方法如下:

cgi_sapi_module.startup(&cgi_sapi_module)   //  cgi模式 cgi/cgi_main.c文件
 
apache2_sapi_module.startup(&apache2_sapi_module);
 //  apache2服务器  apache2handler/sapi_apache2.c文件

这里的cgi_sapi_module是sapi_module_struct结构体的静态变量。 它的startup方法指向php_cgi_startup函数指针。在这个结构体中除了startup函数指针,还有许多其它方法或字段。 其部分定义如下:

struct _sapi_module_struct {
    char *name;         //  名字(标识用)
    char *pretty_name;  //  更好理解的名字(自己翻译的)
 
    int (*startup)(struct _sapi_module_struct *sapi_module);    //  启动函数
    int (*shutdown)(struct _sapi_module_struct *sapi_module);   //  关闭方法
 
    int (*activate)(TSRMLS_D);  // 激活
    int (*deactivate)(TSRMLS_D);    //  停用
 
    int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC);
     //  不缓存的写操作(unbuffered write)
    void (*flush)(void *server_context);    //  flush
    struct stat *(*get_stat)(TSRMLS_D);     //  get uid
    char *(*getenv)(char *name, size_t name_len TSRMLS_DC); //  getenv
 
    void (*sapi_error)(int type, const char *error_msg, ...);   /* error handler */
 
    int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op,
        sapi_headers_struct *sapi_headers TSRMLS_DC);   /* header handler */
 
     /* send headers handler */
    int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC);
 
    void (*send_header)(sapi_header_struct *sapi_header,
            void *server_context TSRMLS_DC);   /* send header handler */
 
    int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC); /* read POST data */
    char *(*read_cookies)(TSRMLS_D);    /* read Cookies */
 
    /* register server variables */
    void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);
 
    void (*log_message)(char *message);     /* Log message */
    time_t (*get_request_time)(TSRMLS_D);   /* Request Time */
    void (*terminate_process)(TSRMLS_D);    /* Child Terminate */
 
    char *php_ini_path_override;    //  覆盖的ini路径
 
    ...
    ...
};

以上的这些结构在各服务器的接口实现中都有定义。如Apache2的定义:

static sapi_module_struct apache2_sapi_module = {
    "apache2handler",
    "Apache 2.0 Handler",
 
    php_apache2_startup,                /* startup */
    php_module_shutdown_wrapper,            /* shutdown */
 
    ...
}

目前PHP内置的很多SAPI实现都已不再维护或者变的有些非主流了,PHP社区目前正在考虑将一些SAPI移出代码库。 社区对很多功能的考虑是除非真的非常必要,或者某些功能已近非常通用了,否则就在PECL库中, 例如非常流行的APC缓存扩展将进入核心代码库中。

整个SAPI类似于一个面向对象中的模板方法模式的应用。 SAPI.c和SAPI.h文件所包含的一些函数就是模板方法模式中的抽象模板, 各个服务器对于sapi_module的定义及相关实现则是一个个具体的模板。

这样的结构在PHP的源码中有多处使用, 比如在PHP扩展开发中,每个扩展都需要定义一个zend_module_entry结构体。 这个结构体的作用与sapi_module_struct结构体类似,都是一个类似模板方法模式的应用。 在PHP的生命周期中如果需要调用某个扩展,其调用的方法都是zend_module_entry结构体中指定的方法, 如在上一小节中提到的在执行各个扩展的请求初始化时,都是统一调用request_startup_func方法, 而在每个扩展的定义时,都通过宏PHP_RINIT指定request_startup_func对应的函数。 以VLD扩展为例:其请求初始化为PHP_RINIT(vld),与之对应在扩展中需要有这个函数的实现:

PHP_RINIT_FUNCTION(vld) {
}

所以, 我们在写扩展时也需要实现扩展的这些接口,同样,当实现各服务器接口时也需要实现其对应的SAPI。

延伸阅读

此文章所在专题列表如下:

  1. PHP内核探索:从SAPI接口开始
  2. PHP内核探索:一次请求的开始与结束
  3. PHP内核探索:一次请求生命周期
  4. PHP内核探索:单进程SAPI生命周期
  5. PHP内核探索:多进程/线程的SAPI生命周期
  6. PHP内核探索:Zend引擎
  7. PHP内核探索:再次探讨SAPI
  8. PHP内核探索:Apache模块介绍
  9. PHP内核探索:通过mod_php5支持PHP
  10. PHP内核探索:Apache运行与钩子函数
  11. PHP内核探索:嵌入式PHP
  12. PHP内核探索:PHP的FastCGI
  13. PHP内核探索:如何执行PHP脚本
  14. PHP内核探索:PHP脚本的执行细节
  15. PHP内核探索:操作码OpCode
  16. PHP内核探索:PHP里的opcode
  17. PHP内核探索:解释器的执行过程
  18. PHP内核探索:变量概述
  19. PHP内核探索:变量存储与类型
  20. PHP内核探索:PHP中的哈希表
  21. PHP内核探索:理解Zend里的哈希表
  22. PHP内核探索:PHP哈希算法设计
  23. PHP内核探索:翻译一篇HashTables文章
  24. PHP内核探索:哈希碰撞攻击是什么?
  25. PHP内核探索:常量的实现
  26. PHP内核探索:变量的存储
  27. PHP内核探索:变量的类型
  28. PHP内核探索:变量的值操作
  29. PHP内核探索:变量的创建
  30. PHP内核探索:预定义变量
  31. PHP内核探索:变量的检索
  32. PHP内核探索:变量的类型转换
  33. PHP内核探索:弱类型变量的实现
  34. PHP内核探索:静态变量的实现
  35. PHP内核探索:变量类型提示
  36. PHP内核探索:变量的生命周期
  37. PHP内核探索:变量赋值与销毁
  38. PHP内核探索:变量作用域
  39. PHP内核探索:诡异的变量名
  40. PHP内核探索:变量的value和type存储
  41. PHP内核探索:全局变量Global
  42. PHP内核探索:变量类型的转换
  43. PHP内核探索:内存管理开篇
  44. PHP内核探索:Zend内存管理器
  45. PHP内核探索:PHP的内存管理
  46. PHP内核探索:内存的申请与销毁
  47. PHP内核探索:引用计数与写时复制
  48. PHP内核探索:PHP5.3的垃圾回收机制
  49. PHP内核探索:内存管理中的cache
  50. PHP内核探索:写时复制COW机制
  51. PHP内核探索:数组与链表
  52. PHP内核探索:使用哈希表API
  53. PHP内核探索:数组操作
  54. PHP内核探索:数组源码分析
  55. PHP内核探索:函数的分类
  56. PHP内核探索:函数的内部结构
  57. PHP内核探索:函数结构转换
  58. PHP内核探索:定义函数的过程
  59. PHP内核探索:函数的参数
  60. PHP内核探索:zend_parse_parameters函数
  61. PHP内核探索:函数返回值
  62. PHP内核探索:形参return value
  63. PHP内核探索:函数调用与执行
  64. PHP内核探索:引用与函数执行
  65. PHP内核探索:匿名函数及闭包
  66. PHP内核探索:面向对象开篇
  67. PHP内核探索:类的结构和实现
  68. PHP内核探索:类的成员变量
  69. PHP内核探索:类的成员方法
  70. PHP内核探索:类的原型zend_class_entry
  71. PHP内核探索:类的定义
  72. PHP内核探索:访问控制
  73. PHP内核探索:继承,多态与抽象类
  74. PHP内核探索:魔术函数与延迟绑定
  75. PHP内核探索:保留类与特殊类
  76. PHP内核探索:对象
  77. PHP内核探索:创建对象实例
  78. PHP内核探索:对象属性读写
  79. PHP内核探索:命名空间
  80. PHP内核探索:定义接口
  81. PHP内核探索:继承与实现接口
  82. PHP内核探索:资源resource类型
  83. PHP内核探索:Zend虚拟机
  84. PHP内核探索:虚拟机的词法解析
  85. PHP内核探索:虚拟机的语法分析
  86. PHP内核探索:中间代码opcode的执行
  87. PHP内核探索:代码的加密与解密
  88. PHP内核探索:zend_execute的具体执行过程
  89. PHP内核探索:变量的引用与计数规则
  90. PHP内核探索:新垃圾回收机制说明

本文地址:http://www.nowamagic.net/librarys/veda/detail/1292,欢迎访问原出处。

不打个分吗?

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/1292

如果你认为这篇文章值得更多人阅读,欢迎使用下面的分享功能。
小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏

大家都在看

阅读一百本计算机著作吧,少年

很多人觉得自己技术进步很慢,学习效率低,我觉得一个重要原因是看的书少了。多少是多呢?起码得看3、4、5、6米吧。给个具体的数量,那就100本书吧。很多人知识结构不好而且不系统,因为在特定领域有一个足够量的知识量+足够良好的知识结构,系统化以后就足以应对大量未曾遇到过的问题。

奉劝自学者:构建特定领域的知识结构体系的路径中再也没有比学习该专业的专业课程更好的了。如果我的知识结构体系足以囊括面试官的大部分甚至吞并他的知识结构体系的话,读到他言语中的一个词我们就已经知道他要表达什么,我们可以让他坐“上位”毕竟他是面试官,但是在知识结构体系以及心理上我们就居高临下。

所以,阅读一百本计算机著作吧,少年!

《编译原理(第2版)》 Alfred V. Aho (作者), Monica S.Lam (作者), 赵建华 (译者), 郑滔 (译者), 戴新宇 (译者)

《编译原理(第2版)》全面、深入地探讨了编译器设计方面的重要主题,包括词法分析、语法分析、语法制导定义和语法制导翻译、运行时刻环境、目标代码生成、代码优化技术、并行性检测以及过程间分析技术,并在相关章节中给出大量的实例。与上一版相比,《编译原理(第2版)》进行了全面的修订,涵盖了编译器开发方面的最新进展。每章中都提供了大量的系统及参考文献。《编译原理(第2版)》是编译原理课程方面的经典教材,内容丰富,适合作为高等院校计算机及相关专业本科生及研究生的编译原理课程的教材,也是广大技术人员的极佳参考读物。

更多计算机宝库...