1. 程式人生 > >跟廠長學PHP7內核(五):一步步分析生命周期之模塊初始化階段

跟廠長學PHP7內核(五):一步步分析生命周期之模塊初始化階段

hle 持久 globals .post lean nco ror sign trie

上篇我們講到了模塊初始化階段,並得知它是由php_module_startup函數來實現的。該階段的主要作用是初始化變量、常量;註冊各種函數,比如工具、詞法、語法函數等;解析配置文件;加載擴展;當然最重要的是計算出PHP二進制程序的路徑,現在讓我們來研究一下該函數都做了哪些工作。

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宏中的成員變量進行初始化。

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_response_code = 200;
    */
    SG(sapi_headers).http_status_line = NULL;
    SG(sapi_headers).mimetype = NULL;
    SG(headers_sent) = 0;
    ZVAL_UNDEF(&SG(callback_func));
    SG(read_post_bytes) = 0;
    SG(request_info).request_body = NULL;
    SG(request_info).current_user = NULL;
    SG(request_info).current_user_length = 0;
    SG(request_info).no_headers = 0;
    SG(request_info).post_entry = NULL;
    SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
    SG(global_request_time) = 0;
    SG(post_read) = 0;
    /* It's possible to override this general case in the activate() callback, if necessary. */
    if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
        SG(request_info).headers_only = 1;
    } else {
        SG(request_info).headers_only = 0;
    }
    SG(rfc1867_uploaded_files) = NULL;

    /* Handle request method */
    if (SG(server_context)) {
        if (PG(enable_post_data_reading)
        &&  SG(request_info).content_type
        &&  SG(request_info).request_method
        && !strcmp(SG(request_info).request_method, "POST")) {
            /* HTTP POST may contain form data to be processed into variables
             * depending on given content type */
            sapi_read_post_data();
        } else {
            SG(request_info).content_type_dup = NULL;
        }

        /* Cookies */
        SG(request_info).cookie_data = sapi_module.read_cookies();

        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 */

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;
}

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_globalscore_globals又對應_php_core_globals,代碼如下

extern ZEND_API struct _php_core_globals core_globals;

php_core_globals顧名思義,就是php核心的全局變量,定義很多PHP相關的參數,比如內存上限、是否顯示錯誤信息、上傳文件大小限制、輸入輸出編碼、禁用的函數等等,這裏不再贅述,感興趣的同學可以去看一下源碼。

//main/php_globals.h
struct _php_core_globals {
    zend_bool implicit_flush;

    zend_long output_buffering;

    zend_bool sql_safe_mode;
    zend_bool enable_dl;

    char *output_handler;

    char *unserialize_callback_func;
    zend_long serialize_precision;

    zend_long memory_limit;
    zend_long max_input_time;

    zend_bool track_errors;
    zend_bool display_errors;
    zend_bool display_startup_errors;
    zend_bool log_errors;
    zend_long      log_errors_max_len;
    zend_bool ignore_repeated_errors;
    zend_bool ignore_repeated_source;
    zend_bool report_memleaks;
    char *error_log;

    char *doc_root;
    char *user_dir;
    char *include_path;
    char *open_basedir;
    char *extension_dir;
    char *php_binary;
    char *sys_temp_dir;

    char *upload_tmp_dir;
    zend_long upload_max_filesize;

    char *error_append_string;
    char *error_prepend_string;

    char *auto_prepend_file;
    char *auto_append_file;

    char *input_encoding;
    char *internal_encoding;
    char *output_encoding;

    arg_separators arg_separator;

    char *variables_order;

    HashTable rfc1867_protected_variables;

    short connection_status;
    short ignore_user_abort;

    unsigned char header_is_being_sent;

    zend_llist tick_functions;

    zval http_globals[6];

    zend_bool expose_php;

    zend_bool register_argc_argv;
    zend_bool auto_globals_jit;

    char *docref_root;
    char *docref_ext;

    zend_bool html_errors;
    zend_bool xmlrpc_errors;

    zend_long xmlrpc_error_number;

    zend_bool activated_auto_globals[8];

    zend_bool modules_activated;
    zend_bool file_uploads;
    zend_bool during_request_startup;
    zend_bool allow_url_fopen;
    zend_bool enable_post_data_reading;
    zend_bool report_zend_debug;

    int last_error_type;
    char *last_error_message;
    char *last_error_file;
    int  last_error_lineno;

    char *php_sys_temp_dir;

    char *disable_functions;
    char *disable_classes;
    zend_bool allow_url_include;
    zend_bool exit_on_timeout;
#ifdef PHP_WIN32
    zend_bool com_initialized;
#endif
    zend_long max_input_nesting_level;
    zend_long max_input_vars;
    zend_bool in_user_include;

    char *user_ini_filename;
    zend_long user_ini_cache_ttl;

    char *request_order;

    zend_bool mail_x_header;
    char *mail_log;

    zend_bool in_error_log;

#ifdef PHP_WIN32
    zend_bool windows_show_crt_warning;
#endif
};

php_startup_ticks函數就是對PG宏的成員變量tick_functions進行初始化。

5、gc_globals_ctor函數

ZEND_API void gc_globals_ctor(void)
{
    gc_globals_ctor_ex(&gc_globals);
}

這裏又出現了一個gc_globals,PHP的全局變量就是多啊,在這裏我們只要先記住它是PHP垃圾回收相關的結構體即可,後面我們做詳細介紹。這段代碼是對gc_globals進行初始化。

//Zend/zend_gc.c
typedef struct _zend_gc_globals {
    zend_bool         gc_enabled;
    zend_bool         gc_active;
    zend_bool         gc_full;

    gc_root_buffer   *buf;              /* preallocated arrays of buffers   */
    gc_root_buffer    roots;            /* list of possible roots of cycles */
    gc_root_buffer   *unused;           /* list of unused buffers           */
    gc_root_buffer   *first_unused;     /* pointer to first unused buffer   */
    gc_root_buffer   *last_unused;      /* pointer to last unused buffer    */

    gc_root_buffer    to_free;          /* list to free                     */
    gc_root_buffer   *next_to_free;

    uint32_t gc_runs;
    uint32_t collected;

#if GC_BENCH
    uint32_t root_buf_length;
    uint32_t root_buf_peak;
    uint32_t zval_possible_root;
    uint32_t zval_buffered;
    uint32_t zval_remove_from_buffer;
    uint32_t zval_marked_grey;
#endif

} zend_gc_globals;

6、zend_startup函數

6.1、start_memory_manager

初始化內存管理器,對結構體alloc_globals進行初始化。

//Zend/zend_alloc.c
static void alloc_globals_ctor(zend_alloc_globals *alloc_globals)
{
#if ZEND_MM_CUSTOM
    char *tmp = getenv("USE_ZEND_ALLOC");

    if (tmp && !zend_atoi(tmp, 0)) {
        alloc_globals->mm_heap = malloc(sizeof(zend_mm_heap));
        memset(alloc_globals->mm_heap, 0, sizeof(zend_mm_heap));
        alloc_globals->mm_heap->use_custom_heap = ZEND_MM_CUSTOM_HEAP_STD;
        alloc_globals->mm_heap->custom_heap.std._malloc = __zend_malloc;
        alloc_globals->mm_heap->custom_heap.std._free = free;
        alloc_globals->mm_heap->custom_heap.std._realloc = __zend_realloc;
        return;
    }
#endif
#ifdef MAP_HUGETLB
    tmp = getenv("USE_ZEND_ALLOC_HUGE_PAGES");
    if (tmp && zend_atoi(tmp, 0)) {
        zend_mm_use_huge_pages = 1;
    }
#endif
    ZEND_TSRMLS_CACHE_UPDATE();
    alloc_globals->mm_heap = zend_mm_init();
}

6.2、virtual_cwd_startup

virtual_cwd_startup初始化了cwd_globals,根據源碼可以看出成員變量都與realpath_cache有關,realpath_cache是什麽呢?我們平時在寫代碼的時候,經常會使用include、include_once、require、require_once等語句導入文件,如果每次使用這些語句都要去對應的目錄中尋找目標文件,勢必會降低性能,所以官方加入了緩存,以便PHP再次使用時不必到include_path中查找,加快PHP的執行速度。

//Zend/zend_virtual_cwd.c
typedef struct _virtual_cwd_globals {
    cwd_state cwd;
    zend_long                   realpath_cache_size;
    zend_long                   realpath_cache_size_limit;
    zend_long                   realpath_cache_ttl;
    realpath_cache_bucket *realpath_cache[1024];
} virtual_cwd_globals;

6.3、zend_startup_extensions_mechanism

啟動擴展機制,初始化zend_extensions結構體

int zend_startup_extensions_mechanism()
{
    /* Startup extensions mechanism */
    zend_llist_init(&zend_extensions, sizeof(zend_extension), (void (*)(void *)) zend_extension_dtor, 1);
    last_resource_number = 0;
    return SUCCESS;
}

6.4、提供編譯與執行入口

zend_compile_file = compile_file;
zend_execute_ex = execute_ex;

6.5、zend_init_opcodes_handlers

初始化Zend虛擬機的handler

6.6、初始化CG、EG

初始化CG(function_table)、CG(class_table)、CG(auto_globals)、EG(zend_constants),這裏不再贅述,我們後續講解。

GLOBAL_FUNCTION_TABLE = (HashTable *) malloc(sizeof(HashTable));
GLOBAL_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable));
GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable));
GLOBAL_CONSTANTS_TABLE = (HashTable *) malloc(sizeof(HashTable));

6.7、ini_scanner_globals_ctor

初始化ini_scanner_globals

6.8、php_scanner_globals_ctor

初始化language_scanner_globals

6.9、zend_set_default_compile_time_values

設置了編譯相關的配置

//Zend/zend.c
static void zend_set_default_compile_time_values(void) /* {{{ */
{
    /* default compile-time values */
    CG(short_tags) = short_tags_default;
    CG(compiler_options) = compiler_options_default;
}

6.10、EG(error_reporting) = E_ALL & ~E_NOTICE;

EG宏就是executor_globals,Zend執行器相關的全局變量,在這裏對我們熟知的error_reporting進行配置。

//Zend/zend_globals.h
struct _zend_executor_globals {
    zval uninitialized_zval;
    zval error_zval;

    /* symbol table cache */
    zend_array *symtable_cache[SYMTABLE_CACHE_SIZE];
    zend_array **symtable_cache_limit;
    zend_array **symtable_cache_ptr;
    ......
}

6.11、zend_interned_strings_init

初始化內部字符串

//Zend/zend_string.c
void zend_interned_strings_init(void)
{
#ifndef ZTS
    zend_string *str;

    zend_hash_init(&CG(interned_strings), 1024, NULL, _str_dtor, 1);
    ......
}

6.12、zend_startup_builtin_functions

初始化內部函數

//Zend/zend_builtin_functions.c
int zend_startup_builtin_functions(void) /* {{{ */
{
    zend_builtin_module.module_number = 0;
    zend_builtin_module.type = MODULE_PERSISTENT;
    return (EG(current_module) = zend_register_module_ex(&zend_builtin_module)) == NULL ? FAILURE : SUCCESS;
}

6.13、zend_register_standard_constants

註冊常量,比如E_ERROR、E_WARNING、E_NOTICE、E_CORE_ERROR等。

//Zend/zend_constants.c
void zend_register_standard_constants(void)
{
    REGISTER_MAIN_LONG_CONSTANT("E_ERROR", E_ERROR, CONST_PERSISTENT | CONST_CS);
    REGISTER_MAIN_LONG_CONSTANT("E_RECOVERABLE_ERROR", E_RECOVERABLE_ERROR, CONST_PERSISTENT | CONST_CS);
    REGISTER_MAIN_LONG_CONSTANT("E_WARNING", E_WARNING, CONST_PERSISTENT | CONST_CS);
    ......
}

6.14、zend_register_auto_global

將GLOBALS加入CG(auto_globals)

//Zend/zend.c
zend_register_auto_global(zend_string_init("GLOBALS", sizeof("GLOBALS") - 1, 1), 1, php_auto_globals_create_globals);

6.15、zend_init_rsrc_plist

初始化持久化符號表

int zend_init_rsrc_plist(void)
{
    zend_hash_init_ex(&EG(persistent_list), 8, NULL, plist_entry_destructor, 1, 0);
    return SUCCESS;
}

6.16、zend_init_exception_op

初始化EG(exception_op)

6.17、zend_init_call_trampoline_op

初始化EG(call_trampoline_op)

6.18、zend_ini_startup

初始化與php.ini解析相關的變量

//Zend/zend_ini.c
ZEND_API int zend_ini_startup(void) /* {{{ */
{
    registered_zend_ini_directives = (HashTable *) malloc(sizeof(HashTable));

    EG(ini_directives) = registered_zend_ini_directives;
    EG(modified_ini_directives) = NULL;
    EG(error_reporting_ini_entry) = NULL;
    zend_hash_init_ex(registered_zend_ini_directives, 128, NULL, free_ini_entry, 1, 0);
    return SUCCESS;
}

7、zend_register_list_destructors_ex函數

初始化析構函數

//Zend/zend_list.c
ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld, rsrc_dtor_func_t pld, const char *type_name, int module_number)
{
    zend_rsrc_list_dtors_entry *lde;
    zval zv;

    lde = malloc(sizeof(zend_rsrc_list_dtors_entry));
    lde->list_dtor_ex = ld;
    lde->plist_dtor_ex = pld;
    lde->module_number = module_number;
    lde->resource_id = list_destructors.nNextFreeElement;
    lde->type_name = type_name;
    ZVAL_PTR(&zv, lde);

    if (zend_hash_next_index_insert(&list_destructors, &zv) == NULL) {
        return FAILURE;
    }
    return list_destructors.nNextFreeElement-1;
}

8、php_binary_init函數

獲取PHP執行的二進制路徑

static void php_binary_init(void)
{
    char *binary_location;
#ifdef PHP_WIN32
    binary_location = (char *)malloc(MAXPATHLEN);
    if (GetModuleFileName(0, binary_location, MAXPATHLEN) == 0) {
        free(binary_location);
        PG(php_binary) = NULL;
    }
#else
    if (sapi_module.executable_location) {
        binary_location = (char *)malloc(MAXPATHLEN);
        if (!strchr(sapi_module.executable_location, '/')) {
            char *envpath, *path;
            int found = 0;
            ......
}

9、php_output_register_constants函數

初始化輸出相關的預定義常量

//main/output.c
PHPAPI void php_output_register_constants(void)
{
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_WRITE", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSH", PHP_OUTPUT_HANDLER_FLUSH, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEAN", PHP_OUTPUT_HANDLER_CLEAN, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FINAL", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);

    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEANABLE", PHP_OUTPUT_HANDLER_CLEANABLE, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSHABLE", PHP_OUTPUT_HANDLER_FLUSHABLE, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_REMOVABLE", PHP_OUTPUT_HANDLER_REMOVABLE, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STDFLAGS", PHP_OUTPUT_HANDLER_STDFLAGS, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STARTED", PHP_OUTPUT_HANDLER_STARTED, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_DISABLED", PHP_OUTPUT_HANDLER_DISABLED, CONST_CS | CONST_PERSISTENT);
}

10、php_rfc1867_register_constants函數

註冊文件上傳相關的預定義常量

//main/rfc1867.c
void php_rfc1867_register_constants(void) /* {{{ */
{
    REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_OK",         UPLOAD_ERROR_OK, CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_INI_SIZE",   UPLOAD_ERROR_A,  CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FORM_SIZE",  UPLOAD_ERROR_B,  CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL",    UPLOAD_ERROR_C,  CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE",    UPLOAD_ERROR_D,  CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E,  CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F,  CONST_CS | CONST_PERSISTENT);
    REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION",  UPLOAD_ERROR_X,  CONST_CS | CONST_PERSISTENT);
}

11、php_init_config函數

初始化配置文件php.ini,並通過zend_parse_ini_file解析。

12、zend_register_standard_ini_entries函數

初始化ini相關的變量

void zend_register_standard_ini_entries(void) /* {{{ */
{
    int module_number = 0;

    REGISTER_INI_ENTRIES();
}

13、php_startup_auto_globals函數

註冊我們熟知的全局變量$_GET、$_POST、$_COOKIE等等

//main/php_variables.c
void php_startup_auto_globals(void)
{
    zend_register_auto_global(zend_string_init("_GET", sizeof("_GET")-1, 1), 0, php_auto_globals_create_get);
    zend_register_auto_global(zend_string_init("_POST", sizeof("_POST")-1, 1), 0, php_auto_globals_create_post);
    zend_register_auto_global(zend_string_init("_COOKIE", sizeof("_COOKIE")-1, 1), 0, php_auto_globals_create_cookie);
    zend_register_auto_global(zend_string_init("_SERVER", sizeof("_SERVER")-1, 1), PG(auto_globals_jit), php_auto_globals_create_server);
    zend_register_auto_global(zend_string_init("_ENV", sizeof("_ENV")-1, 1), PG(auto_globals_jit), php_auto_globals_create_env);
    zend_register_auto_global(zend_string_init("_REQUEST", sizeof("_REQUEST")-1, 1), PG(auto_globals_jit), php_auto_globals_create_request);
    zend_register_auto_global(zend_string_init("_FILES", sizeof("_FILES")-1, 1), 0, php_auto_globals_create_files);
}

14、php_startup_sapi_content_types函數

初始化針對不同內容類型的處理函數

//main/php_content_types.c
int php_startup_sapi_content_types(void)
{
    sapi_register_default_post_reader(php_default_post_reader);
    sapi_register_treat_data(php_default_treat_data);
    sapi_register_input_filter(php_default_input_filter, NULL);
    return SUCCESS;
}

15、php_register_internal_extensions_func函數

註冊內部擴展函數

16、php_register_extensions_bc函數

註冊PHP的附加擴展

17、zend_startup_modules函數

啟動Zend模塊

18、zend_startup_extensions函數

啟動Zend擴展

19、php_disable_functions函數

對PHP的禁用函數進行設置

static void php_disable_functions(void)
{
    char *s = NULL, *e;

    if (!*(INI_STR("disable_functions"))) {
        return;
    }

    e = PG(disable_functions) = strdup(INI_STR("disable_functions"));
    if (e == NULL) {
        return;
    }
    while (*e) {
        switch (*e) {
            case ' ':
            case ',':
                if (s) {
                    *e = '\0';
                    zend_disable_function(s, e-s);
                    s = NULL;
                }
                break;
            default:
                if (!s) {
                    s = e;
                }
                break;
        }
        e++;
    }
    if (s) {
        zend_disable_function(s, e-s);
    }
}

20、php_disable_classes函數

對PHP的禁用類進行設置

static void php_disable_classes(void)
{
    char *s = NULL, *e;

    if (!*(INI_STR("disable_classes"))) {
        return;
    }

    e = PG(disable_classes) = strdup(INI_STR("disable_classes"));

    while (*e) {
        switch (*e) {
            case ' ':
            case ',':
                if (s) {
                    *e = '\0';
                    zend_disable_class(s, e-s);
                    s = NULL;
                }
                break;
            default:
                if (!s) {
                    s = e;
                }
                break;
        }
        e++;
    }
    if (s) {
        zend_disable_class(s, e-s);
    }
}

跟廠長學PHP7內核(五):一步步分析生命周期之模塊初始化階段