《PHP扩展开发及内核应用》学习笔记(一)

教程地址:PHP扩展开发及内核应用

一、PHP的生命周期

PHP架构图

PHP架构图

简单来说,就是Apache/Nginx启动后,PHP解释程序也随之启动(初始化一些环境变量用于整个SAPI生命周期,以及初始化只针对当前请求的一些变量设置),随着页面执行到页面执行完毕,PHP会自动unset掉各个变量,当请求结束后,关闭各个扩展,从而释放各个模块的内存。

PHP的生命周期

接下来,就跟着教程,痛并快乐的学习下,PHP的生命周期到底是怎么样的。


1. SAPI
static sapi_module_struct cgi_sapi_module = {
#if PHP_FASTCGI
    "cgi-fcgi",                     /* name */
    "CGI/FastCGI",                  /* pretty name */
#else
    "cgi",                          /* name */
    "CGI",                          /* pretty name */
#endif
 
    php_cgi_startup,                /* startup,调用了PHP的初始化函数 */
    php_module_shutdown_wrapper,    /* shutdown,PHP关闭函数的简单封装 */
 
    sapi_cgi_activate,              /* activate,处理一些初始化,资源分配的事务 */
    sapi_cgi_deactivate,            /* deactivate,提供一个handler, 用来处理收尾工作 */
 
    sapi_cgibin_ub_write,           /* unbuffered write,这个hanlder告诉了Zend,如何输出数据 */
    sapi_cgibin_flush,              /* flush,提供给Zend的刷新缓存的函数句柄 */
    NULL,                           /* get uid,让Zend可以验证一个要执行脚本文件的state,从而判断文件是否据有执行权限等等 */
    sapi_cgibin_getenv,             /* getenv,为Zend提供了一个根据name来查找环境变量的接口 */
 
    php_error,                      /* error handler,错误处理函数 */
 
    NULL,                           /* header handler,会在调用PHP的header()函数的时候被调用 */
    sapi_cgi_send_headers,          /* send headers handler,会在要真正发送header的时候被调用 */
    NULL,                           /* send header handler,用来单独发送每一个header */
 
    sapi_cgi_read_post,             /* read POST data,这个句柄指明了如何获取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
};

PS:该文件一般位置/.local/share/Trash/files/php-7.1.11/sapi/cgi/


2. PHP的启动与终止

下面直接引用原文中的代码,简单明了,清晰易懂。

//这些代码都在walu.c里面,不再.h里
 
int time_of_minit;//在MINIT中初始化,在每次页面请求中输出,看看是否变化
PHP_MINIT_FUNCTION(walu)
{
    time_of_minit=time(NULL);//我们在MINIT启动中对他初始化
    return SUCCESS;
}
 
int time_of_rinit;//在RINIT里初始化,看看每次页面请求的时候变不。
PHP_RINIT_FUNCTION(walu)
{
    time_of_rinit=time(NULL);
    return SUCCESS;
}
 
PHP_RSHUTDOWN_FUNCTION(walu)
{
    FILE *fp=fopen("/cnan/www/erzha/time_rshutdown.txt","a+");//请确保文件可写,否则apache会莫名崩溃
    fprintf(fp,"%d\n",time(NULL));//让我们看看是不是每次请求结束都会在这个文件里追加数据
    fclose(fp);
    return SUCCESS;
}
 
PHP_MSHUTDOWN_FUNCTION(walu)
{
    FILE *fp=fopen("/cnan/www/erzha/time_mshutdown.txt","a+");//请确保文件可写,否则apache会莫名崩溃
    fprintf(fp,"%d\n",time(NULL));
    return SUCCESS;
}
 
//我们在页面里输出time_of_minit和time_of_rinit的值
PHP_FUNCTION(walu_test)
{
    php_printf("%d<br />",time_of_minit);
    php_printf("%d<br />",time_of_rinit);
    return;
}
  • time_of_minit的值每次请求都不变。
  • time_of_rinit的值每次请求都改变。
  • 每次页面请求都会往time_rshutdown.txt中写入数据。
  • 只有在apache结束后time_mshutdown.txt才写入有数据。

3. PHP的生命周期

一个PHP实例,无论是从init脚本中调用的,还是从命令行启动的,都会向我们上一节说的那样, 依次进行Module init、Request init、Request Shutdown、Module shutdown四个过程, 当然之间还会执行脚本自己的逻辑。 那么两种init和两种shutdown各会执行多少次、各自的执行频率有多少呢? 这取决与PHP是用什么sapi与宿主通信的。最常见的四种方式如下所列:

  1. 直接以CLI/CGI模式调用
  2. 多进程模块
  3. 多线程模
  4. Embedded(嵌入式,在自己的C程序中调用Zend Engine)
3.1. 单进程SAPI生命周期

单进程SAPI生命周期

3.2. 多进程模式 & 多线程模式

多进程SPAI生命周期

多进程SPAI生命周期

多线程SAPI生命周期

多线程SAPI生命周期

简单解释下,多进程和多线程:

  • 进程(process)是资源分配的最小单位,线程(thread)是处理机调度的最小单位。
  • 一个进程可以有很多线程,每条线程并行执行不同的任务。
  • PHP是单进程执行的,但是当数据量比较大(例如:队列处理、日志分析、文件处理等)或者运行守护进程的时候,就需要依赖服务器或PHP-FPM的多进程及它们进程的复用。

通常PHP是编译为apache的一个模块来处理PHP请求。Apache一般会采用多进程模式,Apache启动后会fork出多个子进程,每个进程的内存空间独立,每个子进程都会经过开始和结束环节,不过每个进程的开始阶段只在进程fork出来以来后进行,在整个进程的生命周期内可能会处理多个请求。
只有在Apache关闭或者进程被结束之后才会进行关闭阶段,在这两个阶段之间会随着每个请求重复请求开始-请求关闭的环节。
多线程模式和多进程中的某个进程类似,不同的是在整个进程的生命周期内会并行的重复着 请求开始-请求关闭的环节。


4. 线性安全

在多线程中,多个线程共享除函数调用栈之外的其他资源。 各种变量的作用域从定义来看如下:

  • 全局变量,所有函数共享,因此所有的线程共享,不同线程中出现的不同变量都是这同一个变量。
  • 静态全局变量,所有函数共享,也是所有线程共享。
  • 局部变量,此函数的各次执行中涉及的这个变量没有联系,因此,也是各个线程间也是不共享的。
  • 静态局部变量,本函数间共享,函数的每次执行涉及的这个变量都是同一个变量,因此,各个线程是共享的。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值