跟厂长学PHP7内核(五):系统分析生命周期

上篇文章讲述了模块初始化阶段之前的准备工作,本篇我来详细介绍PHP生命周期的五个阶段。

一、模块初始化阶段

我们先来看一下该阶段的每个函数的作用。

1.1、sapi_initialize_request_empty函数 // main/SAPI.c SAPI_API void sapi_initialize_empty_request(void) { SG(server_context) = NULL; SG(request_info).request_method = NULL; SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL; SG(request_info).content_type_dup = NULL; }

这个函数主要为前面定义的SG宏中的成员变量进行初始化。

1.2、sapi_activate函数 // main/SAPI.c SAPI_API void sapi_activate(void) { zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0); SG(sapi_headers).send_default_content_type = 1; SG(sapi_headers).http_status_line = NULL; SG(sapi_headers).mimetype = NULL; SG(headers_sent) = 0; ...... /* Handle request method */ if (SG(server_context)) { ...... if (sapi_module.activate) { sapi_module.activate(); } } if (sapi_module.input_filter_init) { sapi_module.input_filter_init(); } }

函数的前半部分主要还是对SG宏的成员变量进行初始化。后半部分先是调用了sapi_module_struct内部实现的activate函数,又调用了input_filter_init函数,但是在CLI模式并没有实现这两个函数,只是返回了NULL。代码如下:

NULL, /* activate */ 1.3、php_output_startup函数 //main/output.c PHPAPI void php_output_startup(void) { ZEND_INIT_MODULE_GLOBALS(output, php_output_init_globals, NULL); zend_hash_init(&php_output_handler_aliases, 8, NULL, NULL, 1); zend_hash_init(&php_output_handler_conflicts, 8, NULL, NULL, 1); zend_hash_init(&php_output_handler_reverse_conflicts, 8, NULL, reverse_conflict_dtor, 1); php_output_direct = php_output_stdout; }

我们先来看ZEND_INIT_MODULE_GLOBALS宏做了什么事情:

#define ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor, globals_dtor) \ globals_ctor(&module_name##_globals);

由代码得知,该宏只是做了一层替换,替换后的内容为:

php_output_init_globals(&output_globals);

那php_output_init_globals函数又做了什么呢?

//main/output.c static inline void php_output_init_globals(zend_output_globals *G) { ZEND_TSRMLS_CACHE_UPDATE(); memset(G, 0, sizeof(*G)); }

该函数通过memset函数对output_globals进行了内存相关的初始化,我们可以在main/php_output.h中的155行找到它的宏定义OG。

//main/php_output.h # define OG(v) (output_globals.v)

OG对应的结构体是php_output_init_globals的入参zend_output_globals,在这里花了些时间,因为没找到定义在哪里,最后发现它也是通过宏定义替换得来的,代码如下:

//main/php_output.h ZEND_BEGIN_MODULE_GLOBALS(output) zend_stack handlers; php_output_handler *active; php_output_handler *running; const char *output_start_filename; int output_start_lineno; int flags; ZEND_END_MODULE_GLOBALS(output)

看似是定义了一个结构体,但是代码中又出现了两个宏,我们再来瞅瞅这两个宏是干嘛的:

//Zend/zend_API.h #define ZEND_BEGIN_MODULE_GLOBALS(module_name) \ typedef struct _zend_##module_name##_globals { #define ZEND_END_MODULE_GLOBALS(module_name) \ } zend_##module_name##_globals;

原来只是做了个替换而已,替换后的代码如下:

//这个是意淫出来的代码 typedef struct _zend_output_globals { zend_stack handlers; php_output_handler *active; php_output_handler *running; const char *output_start_filename; int output_start_lineno; int flags; } zend_output_globals

这才是zend_output_globals最纯粹的定义,写的很是骚气,差点看断片。这样看来我们的OG宏对应的就是这个结构体了,姑且认为它是PHP输出相关的结构体。我们继续往下看:

zend_hash_init(&php_output_handler_aliases, 8, NULL, NULL, 1); zend_hash_init(&php_output_handler_conflicts, 8, NULL, NULL, 1); zend_hash_init(&php_output_handler_reverse_conflicts, 8, NULL, reverse_conflict_dtor, 1); php_output_direct = php_output_stdout;

接下来又对三个HashTable进行了初始化,初始化完成后,将php_output_direct指针指向了php_output_stdout函数。php_output_stdout函数的作用是调用fwrite函数,输出字符串到stdout中。代码如下:

//main/output.c static size_t php_output_stdout(const char *str, size_t str_len) { fwrite(str, 1, str_len, stdout); return str_len; } 1.4、php_startup_ticks函数 int php_startup_ticks(void) { zend_llist_init(&PG(tick_functions), sizeof(struct st_tick_function), NULL, 1); return SUCCESS; }

这里又出现了一个PG宏,来看下它的定义

# define PG(v) (core_globals.v)

PG对应的结构体是core_globals,core_globals又对应_php_core_globals,代码如下

extern ZEND_API struct _php_core_globals core_globals;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxyjx.html