對於PHP的中的數據來源, 不外乎有倆種:
- 1. 來自代碼中
對於代碼中的變量(也就是直接量)來說, 變量分配/賦值在編譯期, 活躍在執行器, 在請求關閉期被銷毀.對於這些變量來說, 使用APC進行Opcode緩存, 則會緩存這部分變量的值.
而對於來自外部的變量, 變量分配/賦值在編譯器後, 執行期前, 在請求關閉期被銷毀,對於這些變量來說, 使用APC進行OpCode緩存, 是不會被緩存的.
今天就著重關注下外部變量的一個部分,GET來的數據的整個生命周期.
假設, 有如下請求到來:
而, 在index.PHP中:
- <?PHP
- $name =
對於PHP的中的數據來源, 不外乎有倆種:
- 1. 來自代碼中
對於代碼中的變量(也就是直接量)來說, 變量分配/賦值在編譯期, 活躍在執行器, 在請求關閉期被銷毀.對於這些變量來說, 使用APC進行Opcode緩存, 則會緩存這部分變量的值.
而對於來自外部的變量, 變量分配/賦值在編譯器後, 執行期前, 在請求關閉期被銷毀,對於這些變量來說, 使用APC進行OpCode緩存, 是不會被緩存的.
今天就著重關注下外部變量的一個部分,GET來的數據的整個生命周期.
假設, 有如下請求到來:
而, 在index.PHP中:
___FCKpd___2我們知道, 在最後的執行期, $_GET數組必然包含如下片段:
對於PHP的中的數據來源, 不外乎有倆種:
- 1. 來自代碼中
對於代碼中的變量(也就是直接量)來說, 變量分配/賦值在編譯期, 活躍在執行器, 在請求關閉期被銷毀.對於這些變量來說, 使用APC進行Opcode緩存, 則會緩存這部分變量的值.
而對於來自外部的變量, 變量分配/賦值在編譯器後, 執行期前, 在請求關閉期被銷毀,對於這些變量來說, 使用APC進行OpCode緩存, 是不會被緩存的.
今天就著重關注下外部變量的一個部分,GET來的數據的整個生命周期.
假設, 有如下請求到來:
而, 在index.PHP中:
- <?PHP
- $name =
對於PHP的中的數據來源, 不外乎有倆種:
- 1. 來自代碼中
對於代碼中的變量(也就是直接量)來說, 變量分配/賦值在編譯期, 活躍在執行器, 在請求關閉期被銷毀.對於這些變量來說, 使用APC進行Opcode緩存, 則會緩存這部分變量的值.
而對於來自外部的變量, 變量分配/賦值在編譯器後, 執行期前, 在請求關閉期被銷毀,對於這些變量來說, 使用APC進行OpCode緩存, 是不會被緩存的.
今天就著重關注下外部變量的一個部分,GET來的數據的整個生命周期.
假設, 有如下請求到來:
而, 在index.PHP中:
___FCKpd___2我們知道, 在最後的執行期, $_GET數組必然包含如下片段:
___FCKpd___3那麼, 我們今天就重點關注下, Query String是如何構建成_GET數組的(關於GET變量的生成, 請一並閱讀我之前的文章: “PHP的GET/POST等大變量生成過程“):
在請求到來時刻,PHP_request_startup(定義在main.c)被調用,來做初始化現場. 在這個過程中包括設置超時值,調用各個模塊的請求初始化函數. 當然也包括我們關心的, 創建變量環境.
php_hash_environment根據PHP.ini中的variables_order來依次初始化各個預定義大變量, 那麼對於$_GET來說:
- ...
- case 'g':
- case 'G':
- if (!_gpc_flags[2]) {
- sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);
- _gpc_flags[2] = 1;
- if (PG(register_globals)) {
- PHP_autoglobal_merge(&EG(symbol_table),
- Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]) TSRMLS_CC);
- }
- }
- break;
大體可以看出,這段邏輯,首先通過treat_data來生成變量hash(PG(http_globals)[TRACK_VARS_GET]), 如果打開了auto_register_globals,則再把$_GET數組中的變量加入到符號表中.
treat_data是屬於sapi_module_struct中的一個成員:
- 注意: 本文基於apache2handler方式的sapi, 這個啟動過程和之前的文章sapi
- 原理中的啟動過程略有不同, PHP5通過注冊apache2的ap_hook_post_config掛鉤,
- 在apache server啟動的時候啟動PHP(PHP_apache_server_startup,定義在
- sapi/apache2hander/sapi_apache2.c中), 在這個函數中調用sapi_startup啟動sapi,
- 繼而通過調用PHP_apache2_startup來注冊sapi module struct,
- 然後調用php_module_startup來初始化PHP, 其中又會初始化ZEND引擎,
- 以及填充zend_module_struct中的treat_data成員(通過PHP_startup_sapi_content_types)
現在回過頭來繼續看treat_data(也就是PHP_default_treat_data):
- ....
- if (arg == PARSE_GET) { /* GET data */
- c_var = SG(request_info).query_string;
- if (c_var && *c_var) {
- res = (char *) estrdup(c_var);
- free_buffer = 1;
- } else {
- free_buffer = 0;
- }
- } else if (arg == PARSE_COOKIE) { /* CookIE data */
在上面的邏輯中, 給res復制為query_string, SG(request_info)是一個代表了當前請求信息的結構體, 其中query_string是在PHP_apache_request_ctor中通過復制apache的reqeust_rec結構體中的args而來的.
對於本文的例子來說, 此時res即為”name=laruence&career[]=yahoo&career[]=baidu”,
繼續在treat_data中, 隨後的邏輯是:
- var = PHP_strtok_r(res, separator, &strtok_buf);
- ...
- while (var) {
- val = strchr(var, '=');
- if (arg == PARSE_COOKIE) {
- /* Remove leading spaces from cookIE names,
- needed for multi-cookIE header where ; can be followed by a space */
- while (isspace(*var)) {
- var++;
- }
- if (var == val || *var == '\0') {
- goto next_cookIE;
- }
- }
- if (val) { /* have a value */
- int val_len;
- unsigned int new_val_len;
- *val++ = '\0';
- PHP_url_decode(var, strlen(var));
- val_len = PHP_url_decode(val, strlen(val));
- val = estrndup(val, val_len);
- if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) {
- PHP_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);
- }
- efree(val);
- } else {
首先, 通過php_strtok_r把res根據”&”分割成一個一個的”key=value”段, 接下來分別為var和val復制為key和value, 注意到這個過程中會分別對var和val做PHP_url_decode.
最後通過PHP_register_variable_safe, 給array_ptr(此時指向PG(http_globals)[TRACK_VARS_GET], 也就是$_GET)添加一個名為var值為val的成員.
到了這一步, 我們的$_GET數組中, 就包含了如下的成員:
- 'name' => 'laruence',
- 'career' => array(
- 'yahoo', 'baidu',
未完待續(變量的銷毀過程)…
GET['name'];我們知道, 在最後的執行期, $_GET數組必然包含如下片段:
___FCKpd___3那麼, 我們今天就重點關注下, Query String是如何構建成_GET數組的(關於GET變量的生成, 請一並閱讀我之前的文章: “PHP的GET/POST等大變量生成過程“):
在請求到來時刻,PHP_request_startup(定義在main.c)被調用,來做初始化現場. 在這個過程中包括設置超時值,調用各個模塊的請求初始化函數. 當然也包括我們關心的, 創建變量環境.
php_hash_environment根據PHP.ini中的variables_order來依次初始化各個預定義大變量, 那麼對於$_GET來說:
___FCKpd___4大體可以看出,這段邏輯,首先通過treat_data來生成變量hash(PG(http_globals)[TRACK_VARS_GET]), 如果打開了auto_register_globals,則再把$_GET數組中的變量加入到符號表中.
treat_data是屬於sapi_module_struct中的一個成員:
___FCKpd___5現在回過頭來繼續看treat_data(也就是PHP_default_treat_data):
___FCKpd___6在上面的邏輯中, 給res復制為query_string, SG(request_info)是一個代表了當前請求信息的結構體, 其中query_string是在PHP_apache_request_ctor中通過復制apache的reqeust_rec結構體中的args而來的.
對於本文的例子來說, 此時res即為”name=laruence&career[]=yahoo&career[]=baidu”,
繼續在treat_data中, 隨後的邏輯是:
___FCKpd___7首先, 通過php_strtok_r把res根據”&”分割成一個一個的”key=value”段, 接下來分別為var和val復制為key和value, 注意到這個過程中會分別對var和val做PHP_url_decode.
最後通過PHP_register_variable_safe, 給array_ptr(此時指向PG(http_globals)[TRACK_VARS_GET], 也就是$_GET)添加一個名為var值為val的成員.
到了這一步, 我們的$_GET數組中, 就包含了如下的成員:
___FCKpd___8未完待續(變量的銷毀過程)…
GET = array(- 'name' => 'laruence',
- 'career' => array(
- 'yahoo', 'baidu',
- ),
那麼, 我們今天就重點關注下, Query String是如何構建成_GET數組的(關於GET變量的生成, 請一並閱讀我之前的文章: “PHP的GET/POST等大變量生成過程“):
在請求到來時刻,PHP_request_startup(定義在main.c)被調用,來做初始化現場. 在這個過程中包括設置超時值,調用各個模塊的請求初始化函數. 當然也包括我們關心的, 創建變量環境.
php_hash_environment根據PHP.ini中的variables_order來依次初始化各個預定義大變量, 那麼對於$_GET來說:
___FCKpd___4大體可以看出,這段邏輯,首先通過treat_data來生成變量hash(PG(http_globals)[TRACK_VARS_GET]), 如果打開了auto_register_globals,則再把$_GET數組中的變量加入到符號表中.
treat_data是屬於sapi_module_struct中的一個成員:
___FCKpd___5現在回過頭來繼續看treat_data(也就是PHP_default_treat_data):
___FCKpd___6在上面的邏輯中, 給res復制為query_string, SG(request_info)是一個代表了當前請求信息的結構體, 其中query_string是在PHP_apache_request_ctor中通過復制apache的reqeust_rec結構體中的args而來的.
對於本文的例子來說, 此時res即為”name=laruence&career[]=yahoo&career[]=baidu”,
繼續在treat_data中, 隨後的邏輯是:
___FCKpd___7首先, 通過php_strtok_r把res根據”&”分割成一個一個的”key=value”段, 接下來分別為var和val復制為key和value, 注意到這個過程中會分別對var和val做PHP_url_decode.
最後通過PHP_register_variable_safe, 給array_ptr(此時指向PG(http_globals)[TRACK_VARS_GET], 也就是$_GET)添加一個名為var值為val的成員.
到了這一步, 我們的$_GET數組中, 就包含了如下的成員:
___FCKpd___8未完待續(變量的銷毀過程)…
GET['name'];
我們知道, 在最後的執行期, $_GET數組必然包含如下片段:
___FCKpd___3
那麼, 我們今天就重點關注下, Query String是如何構建成_GET數組的(關於GET變量的生成, 請一並閱讀我之前的文章: “PHP的GET/POST等大變量生成過程“):
在請求到來時刻,PHP_request_startup(定義在main.c)被調用,來做初始化現場. 在這個過程中包括設置超時值,調用各個模塊的請求初始化函數. 當然也包括我們關心的, 創建變量環境.
php_hash_environment根據PHP.ini中的variables_order來依次初始化各個預定義大變量, 那麼對於$_GET來說:
___FCKpd___4
大體可以看出,這段邏輯,首先通過treat_data來生成變量hash(PG(http_globals)[TRACK_VARS_GET]), 如果打開了auto_register_globals,則再把$_GET數組中的變量加入到符號表中.
treat_data是屬於sapi_module_struct中的一個成員:
___FCKpd___5
現在回過頭來繼續看treat_data(也就是PHP_default_treat_data):
___FCKpd___6
在上面的邏輯中, 給res復制為query_string, SG(request_info)是一個代表了當前請求信息的結構體, 其中query_string是在PHP_apache_request_ctor中通過復制apache的reqeust_rec結構體中的args而來的.
對於本文的例子來說, 此時res即為”name=laruence&career[]=yahoo&career[]=baidu”,
繼續在treat_data中, 隨後的邏輯是:
___FCKpd___7
首先, 通過php_strtok_r把res根據”&”分割成一個一個的”key=value”段, 接下來分別為var和val復制為key和value, 注意到這個過程中會分別對var和val做PHP_url_decode.
最後通過PHP_register_variable_safe, 給array_ptr(此時指向PG(http_globals)[TRACK_VARS_GET], 也就是$_GET)添加一個名為var值為val的成員.
到了這一步, 我們的$_GET數組中, 就包含了如下的成員:
___FCKpd___8
未完待續(變量的銷毀過程)…