跟廠長學PHP核心(四):生命週期之開始前的躁動

來源:互聯網
上載者:User

標籤:檔案   主函數   buffer   write   contex   指令碼   經曆   概覽   儲存   

上一章我們對PHP的源碼目錄結構有了初步瞭解,本章我們繼續從生命週期的維度對PHP進行剖析。

一、概覽

生命週期是什麼呢?你可以把它看作執行過程,PHP的生命週期也就是它從開始執行到結束執行的過程。

PHP生命週期有五個階段,分別為模組初始化階段、請求初始化階段、執行階段、請求關閉階段、模組關閉階段。只是不同SAPI模式下,請求的情況略有不同,比如FastCGI下只經曆了一次模組初始化階段,接下來所有請求只經曆請求初始化、執行指令碼、請求關閉階段。

在初步瞭解生命週期的五個階段之後,我們先來講述在進入模組初始化階段(php_module_startup)之前PHP所做的工作(本文繼續以PHP7.0.12版本的CLI模式)。好了,我們現在開始。

二、源碼分析2.1、sapi_module_struct

cli模式下的入口檔案是sapi/cli/php_cli.c,開啟該檔案,定位到主函數main,有沒有覺得1180行出現的結構體sapi_module_struct很眼熟?這就是上篇文章SAPI的介紹中提到到結構體,它是擴充PHP對外服務的關鍵。

//sapi/cli/php_cli.csapi_module_struct *sapi_module = &cli_sapi_module;

先來看一下sapi_module_structmain/SAPI.h中的定義:

//main/SAPI.hstruct _sapi_module_struct {    char *name; //名字,如cli、fpm等    char *pretty_name;  //更容易理解的名字    int (*startup)(struct _sapi_module_struct *sapi_module);  //模組啟動時調用的函數    int (*shutdown)(struct _sapi_module_struct *sapi_module);  //模組結束時調用的函數    int (*activate)(void);  //處理request時需要調用的函數    int (*deactivate)(void);    //處理完request要調用的函數    size_t (*ub_write)(const char *str, size_t str_length); //用於輸出資料    void (*flush)(void *server_context);    //重新整理緩衝    zend_stat_t *(*get_stat)(void); //判斷對執行的檔案是否有執行許可權    char *(*getenv)(char *name, size_t name_len);   //擷取函數變數的函數指標    void (*sapi_error)(int type, const char *error_msg, ...);   //錯誤處理函數指標    int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers); //調用header()時被調用的函數    int (*send_headers)(sapi_headers_struct *sapi_headers); //發送全部header的函數指標    void (*send_header)(sapi_header_struct *sapi_header, void *server_context);  //發送某一個header的函數指標    size_t (*read_post)(char *buffer, size_t count_bytes);  //擷取HTTP POST中資料的函數指標    char *(*read_cookies)(void);    //擷取COOKIE    void (*register_server_variables)(zval *track_vars_array); //從$_SERVER中擷取變數的函數指標    void (*log_message)(char *message); //輸出錯誤資訊函數指標    double (*get_request_time)(void);   //擷取請求時間的函數指標    void (*terminate_process)(void);    //調用exit退出時的函數指標    char *php_ini_path_override;    //PHP的ini檔案被複寫的地址    void (*block_interruptions)(void);      void (*unblock_interruptions)(void);    void (*default_post_reader)(void);  //負責解析POST資料    void (*treat_data)(int arg, char *str, zval *destArray);    //對資料進行處理    char *executable_location;  //執行的地理位置    int php_ini_ignore; //是否不使用任何ini設定檔    int php_ini_ignore_cwd; //忽略當前路徑的php.ini    int (*get_fd)(int *fd); //擷取執行檔案的fd的函數指標    int (*force_http_10)(void); //強制使用http1.0版本的函數指標    int (*get_target_uid)(uid_t *); //擷取執行程式的uid函數指標    int (*get_target_gid)(gid_t *); //擷取執行程式的gid函數指標    unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len); //對輸入進行過濾的函數指標,比如將輸入參數填充到自動全域變數$_GET、$_POST、$_COOKIE中    void (*ini_defaults)(HashTable *configuration_hash);    int phpinfo_as_text; //是否輸出phpinfo資訊 //預設的ini配置的函數指標,把ini配置資訊在HashTable中    char *ini_entries; //執行時附帶的ini配置,可以使php -d設定    const zend_function_entry *additional_functions; //每個SAPI模組特有的一些函數註冊,比如cli的cli_get_process_title    unsigned int (*input_filter_init)(void);}

SAPI下的每一個模式都實現了該結構體,比如在CLI中:

//sapi/cli/php_cli.cstatic sapi_module_struct cli_sapi_module = {    "cli",                          /* name */    "Command Line Interface",       /* pretty name */    ......}

FPM中:

//sapi/fpm/fpm/fpm_main.cstatic sapi_module_struct cgi_sapi_module = {    "fpm-fcgi",                     /* name */    "FPM/FastCGI",                  /* pretty name */    ......}

在litespeed中也有相同定義:

//sapi/litespeed/lsapi_main.cstatic sapi_module_struct lsapi_sapi_module ={    "litespeed",    "LiteSpeed V6.10",    ......}
2.2、sapi_startup

我們繼續往下看,在經過一系列變數的初始化後,於1302行又調用了sapi_startup函數。

//sapi/cli/php_cli.csapi_startup(sapi_module);

該函數定義了sapi_globals_struct,也就是我們常說的SG宏,它的主要作用是儲存請求的基本資料,比如伺服器資訊、header、編碼等。

//main/SAPI.htypedef struct _sapi_globals_struct {    void *server_context;    sapi_request_info request_info;    sapi_headers_struct sapi_headers;    int64_t read_post_bytes;    unsigned char post_read;    unsigned char headers_sent;    zend_stat_t global_stat;    char *default_mimetype;    char *default_charset;    HashTable *rfc1867_uploaded_files;    zend_long post_max_size;    int options;    zend_bool sapi_started;    double global_request_time;    HashTable known_post_content_types;    zval callback_func;    zend_fcall_info_cache fci_cache;} sapi_globals_struct;
2.3、sapi_module->startup

我們繼續往下看,sapi_module調用了startup函數:

//sapi/cli/php_cli.cif (sapi_module->startup(sapi_module) == FAILURE) {    exit_status = 1;    goto out;}

然後又調用了CLI在sapi_module_struct中定義的startup對應的鉤子函數php_cli_startup

//sapi/cli/php_cli.cstatic sapi_module_struct cli_sapi_module = {    "cli",                          /* name */    "Command Line Interface",       /* pretty name */    php_cli_startup,                /* startup */    ......}

繼續跟進,php_cli_startup函數中又調用了php_module_startup函數:

//sapi/cli/php_cli.cstatic int php_cli_startup(sapi_module_struct *sapi_module) /* {{{ */{    if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {        return FAILURE;    }    return SUCCESS;}
2.4、php_module_startup

是不是很眼熟,這不就是模組初始化階段的函數嘛!原來執行了這麼久才到我們的關鍵點,模組初始化階段內容比較多,我們通過下一章進行詳細剖析。

//main/main.cint php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules){    zend_utility_functions zuf;    zend_utility_values zuv;    int retval = SUCCESS, module_number=0;  /* for REGISTER_INI_ENTRIES() */    char *php_os;    zend_module_entry *module;    ...}

注意:我在本文貼出的代碼都標識了檔案位置,我們可以看出來,在PHP五大生命週期開始之前一直都是在sapi目錄中執行的,而從php_module_struct也就是模組初始化階段開始,才執行到了main目錄,這意味著PHP的生命週期的第一個階段是從main目錄下開始的。

跟廠長學PHP核心(四):生命週期之開始前的躁動

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.