您的位置:首页 > 编程语言 > PHP开发

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

2018-03-16 16:19 429 查看
教程地址:PHP扩展开发及内核应用

一、PHP的生命周期



PHP架构图

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



接下来,就跟着教程,痛并快乐的学习下,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生命周期



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



多进程SPAI生命周期



多线程SAPI生命周期

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

进程(process)是资源分配的最小单位,线程(thread)是处理机调度的最小单位。

一个进程可以有很多线程,每条线程并行执行不同的任务。

PHP是单进程执行的,但是当数据量比较大(例如:队列处理、日志分析、文件处理等)或者运行守护进程的时候,就需要依赖服务器或PHP-FPM的多进程及它们进程的复用。

通常PHP是编译为apache的一个模块来处理PHP请求。Apache一般会采用多进程模式,Apache启动后会fork出多个子进程,每个进程的内存空间独立,每个子进程都会经过开始和结束环节,不过每个进程的开始阶段只在进程fork出来以来后进行,在整个进程的生命周期内可能会处理多个请求。

只有在Apache关闭或者进程被结束之后才会进行关闭阶段,在这两个阶段之间会随着每个请求重复请求开始-请求关闭的环节。

多线程模式和多进程中的某个进程类似,不同的是在整个进程的生命周期内会并行的重复着 请求开始-请求关闭的环节。

4. 线性安全

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

全局变量,所有函数共享,因此所有的线程共享,不同线程中出现的不同变量都是这同一个变量。

静态全局变量,所有函数共享,也是所有线程共享。

局部变量,此函数的各次执行中涉及的这个变量没有联系,因此,也是各个线程间也是不共享的。

静态局部变量,本函数间共享,函数的每次执行涉及的这个变量都是同一个变量,因此,各个线程是共享的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  PHP内核