学了这么久的PHP,你可能不知道它与WE

文章来自:php中文网链接:   以Apache服务器为例,我们看看该服务器是怎样启动PHP,并调用PHP中的方法。Apache服务器启动并运行PHP时,一般是通过mod_php7模块的形式集成(如果是php5.*版本,就是mod_php5模块,模块后缀名根据php版本而定),mod_php7的结构如下(源码路径为php/sapi/apache2handler/mod_PHP7.c):

AP_MODULE_DECLARE_DATAmodulephp7_module={STANDARD20_MODULE_STUFF,/*宏,包括版本,版本,模块索引,模块名,下个模块指针等信息*/create_php_config,/*createper-directoryconfigstructure*/merge_php_config,/*mergeper-directoryconfigstructures*/NULL,/*createper-serverconfigstructure*/NULL,/*mergeper-serverconfigstructures*/php_dir_cmds,/*模块定义的所有指令*/PHP_ap2_register_hook/*registerhooks*/};

  

当Apache需要调用PHP中的方法时,只需要将该请求通过mod_php7模块传达给PHP,PHP层处理完后将数据返回给Apache,整个过程就结束了(补充一下:Apache服务器启动PHP时,其实有两种加载方式,一种为静态加载,一种为动态加载,刚才讨论的mod_php5模块加载方式可以理解为静态加载,也就是需要重新启动Apache服务器,才能将PHP加载进去;动态加载不需要重启服务器,只需要通过发送信号的方式将PHP固定的模块加载到服务器,以达到PHP启动的目的,但是在进行动态加载前,需要将加载模块编译成动态链接库,然后将其配置到服务器的配置文件中)。上面已经给出Apache在PHP中的model结构,下面给出Apache服务器中对应的module结构,如下(该源代码在Apache中,下同):

structmodule_struct{intversion;intminor_version;intmodule_index;constchar*name;void*dynamic_load_handle;structmodule_struct*next;unsignedlongmagic;void(*rewrite_args)(process_rec*process);void*(*create_dir_config)(apr_pool_t*p,char*dir);void*(*merge_dir_config)(apr_pool_t*p,void*base_conf,void*new_conf);void*(*create_server_config)(apr_pool_t*p,server_rec*s);void*(*merge_server_config)(apr_pool_t*p,void*base_conf,void*new_conf);const   将到这里,想必大家已经知道WEB服务器是如何启动PHP,并调用PHP中的方法了哈,下面再给大家讲讲PHP是如何调用WEB服务器接口的。

2.PHP调用WEB服务器接口

  在讲述这个问题前,我们需要了解一下什么是SAPI。SAPI其实是与服务器抽象层之间遵守的共同约定,可以这么简单理解,当PHP需要调用服务器中的方法,例如清除缓存,但是清除缓存的实现方法是在服务器中实现,PHP层根本就不知道怎么调用服务器中的该方法,怎么办?这时双方需要进行约定,然后服务器提供一套约定后的接口给PHP,我们把这些与服务器抽象层之间遵守的共同约定称为SAPI接口。

  问题来了,对于服务器Apache,我们可以提供一套SAPI,但是如果下次又来个其它的服务器,或者其它的“第三方”,那么我们是不是也要给他们提供一套单独的SAPI呢?我们聪明的PHP开发者肯定想到了这一点,即对所有的“第三方”提供一套通用的SAPI接口,但是你可以会问,如果新的“第三方”需要的接口,你的通用SAPI不支持,那怎么办呢,我的理解是将新的功能添加到PHP的通用SAPI接口中,仅仅是个人见解哈,通用SAPI结构如下(源码路径:PHP/main/SAPI.h):

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);//停用void(*flush)(void*server_context);//flushchar*(*read_cookies)(TSRMLS_D);//readCookies//...};

该结构体变量较多,就不一一列举,简要说明一下里面的变量:startup函数是当SAPI初始化时会被调用,shutdown函数是用来释放SAPI的数据结构和内存等,read_cookie是在SAPI激活时被调用,然后将此函数获取的值赋值给SG(request_info).cookie_data。那么对于PHP提供的通用SAPI,Apache服务器又是怎样定制自己的接口呢?具体结构如下(源码路径为PHP/sapi/apache2handler/sapi_apache2.c):

staticsapi_module_structapache2_sapi_module={"apache2handler","Apache2.0Handler",php_apache2_startup,/*startup*/php_module_shutdown_wrapper,/*shutdown*/NULL,/*activate*/NULL,/*deactivate*/php_apache_sapi_ub_write,/*unbufferedwrite*/php_apache_sapi_flush,/*flush*/php_apache_sapi_get_stat,/*getuid*/php_apache_sapi_getenv,/*getenv*/php_error,/*errorhandler*/php_apache_sapi_header_handler,/*headerhandler*/php_apache_sapi_send_headers,/*sendheadershandler*/NULL,/*sendheaderhandler*/php_apache_sapi_read_post,/*readPOSTdata*/php_apache_sapi_read_cookies,/*readCookies*/php_apache_sapi_register_variables,php_apache_sapi_log_message,/*Logmessage*/PHP_apache_sapi_get_request_time,/*RequestTime*/NULL,/*ChildTerminate*/STANDARD_SAPI_MODULE_PROPERTIES};

 

上述源码目录php/sapi/apache2handler/中,目录php/sapi下面放的都是通过SAPI调用的“第三方”,该目录结构如下图所示,目录php/sapi/apache2handler中都是与PHP交互的接口,sapi_apache2.c是PHP与Apache约定的SAPI接口文件。

  

看到这里,大家应该基本清楚PHP层是怎样调用服务器层的接口,为了巩固上面的知识,下面举个栗子,即在Apache服务器环境下读取cookie:

SG(request_info).cookie_data=sapi_module.read_cookies(TSRMLS_C);

对于任意一个服务器在加载时,我们都会指定sapi_module,Apache的sapi_module是apache2_sapi_module,它的read_cookies方法的是php_apache_sapi_read_cookies函数,这样就实现PHP层调用Apache的接口,是不是很简单呢

以上是文章全部内容,有需要学习与经验交流的友友或者进入


转载请注明:http://www.guyukameng.com/aspnet/aspnet/2020-07-28/11443.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了