PHP教程:PHP編程中的變數生存周期

來源:互聯網
上載者:User

對於PHP的中的資料來源, 不外乎有倆種:

  1. 1. 來自代碼中

對於代碼中的變數(也就是直接量)來說, 變數分配/賦值在編譯期, 活躍在執行器, 在請求關閉期被銷毀.對於這些變數來說, 使用APC進行Opcode緩衝, 則會緩衝這部分變數的值.

而對於來自外部的變數, 變數分配/賦值在編譯器後, 執行期前, 在請求關閉期被銷毀,對於這些變數來說, 使用APC進行OpCode緩衝, 是不會被緩衝的.

今天就著重關注下外部變數的一個部分,GET來的資料的整個生命週期.

假設, 有如下請求到來:

     

而, 在index.php中:

  1. <?php
  2.      $name      =

    對於PHP的中的資料來源, 不外乎有倆種:

    1. 1. 來自代碼中

    對於代碼中的變數(也就是直接量)來說, 變數分配/賦值在編譯期, 活躍在執行器, 在請求關閉期被銷毀.對於這些變數來說, 使用APC進行Opcode緩衝, 則會緩衝這部分變數的值.

    而對於來自外部的變數, 變數分配/賦值在編譯器後, 執行期前, 在請求關閉期被銷毀,對於這些變數來說, 使用APC進行OpCode緩衝, 是不會被緩衝的.

    今天就著重關注下外部變數的一個部分,GET來的資料的整個生命週期.

    假設, 有如下請求到來:

       

    而, 在index.php中:

    ___FCKpd___2

    我們知道, 在最後的執行期, $_GET數組必然包含如下片段:

    1.      

      對於PHP的中的資料來源, 不外乎有倆種:

      1. 1. 來自代碼中

      對於代碼中的變數(也就是直接量)來說, 變數分配/賦值在編譯期, 活躍在執行器, 在請求關閉期被銷毀.對於這些變數來說, 使用APC進行Opcode緩衝, 則會緩衝這部分變數的值.

      而對於來自外部的變數, 變數分配/賦值在編譯器後, 執行期前, 在請求關閉期被銷毀,對於這些變數來說, 使用APC進行OpCode緩衝, 是不會被緩衝的.

      今天就著重關注下外部變數的一個部分,GET來的資料的整個生命週期.

      假設, 有如下請求到來:

         

      而, 在index.php中:

      1. <?php
      2.      $name      =

        對於PHP的中的資料來源, 不外乎有倆種:

        1. 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來說:

        1. ...
        2. case 'g':
        3. case 'G':
        4.      if (!_gpc_flags[2]) {
        5.           sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);
        6.           _gpc_flags[2] = 1;
        7.           if (PG(register_globals)) {
        8.                php_autoglobal_merge(&EG(symbol_table),
        9.                     Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]) TSRMLS_CC);
        10.           }
        11.      }
        12. break;

        大體可以看出,這段邏輯,首先通過treat_data來產生變數hash(PG(http_globals)[TRACK_VARS_GET]), 如果開啟了auto_register_globals,則再把$_GET數組中的變數加入到符號表中.

        treat_data是屬於sapi_module_struct中的一個成員:

        1.  注意:     本文基於apache2handler方式的sapi, 這個啟動過程和之前的文章sapi
        2. 原理中的啟動過程略有不同, php5通過註冊apache2的ap_hook_post_config掛鈎,
        3. 在apache server啟動的時候啟動php(php_apache_server_startup,定義在
        4. sapi/apache2hander/sapi_apache2.c中), 在這個函數中調用sapi_startup啟動sapi,
        5. 繼而通過調用php_apache2_startup來註冊sapi module struct,
        6. 然後調用php_module_startup來初始化PHP, 其中又會初始化ZEND引擎,
        7. 以及填充zend_module_struct中的treat_data成員(通過php_startup_sapi_content_types)

        現在回過頭來繼續看treat_data(也就是php_default_treat_data):

        1. ....
        2. if (arg == PARSE_GET) { /* GET data */
        3.      c_var = SG(request_info).query_string;
        4.      if (c_var && *c_var) {
        5.           res = (char *) estrdup(c_var);
        6.           free_buffer = 1;
        7.      } else {
        8.           free_buffer = 0;
        9.      }
        10. } 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中, 隨後的邏輯是:

        1. var = php_strtok_r(res, separator, &strtok_buf);
        2. ...
        3. while (var) {
        4.      val = strchr(var, '=');
        5.  
        6.      if (arg == PARSE_COOKIE) {
        7.           /* Remove leading spaces from cookie names,
        8.                needed for multi-cookie header where ; can be followed by a space */
        9.           while (isspace(*var)) {
        10.                var++;
        11.           }
        12.           if (var == val *var == '\0') {
        13.                goto next_cookie;
        14.           }
        15.      }
        16.  
        17.      if (val) { /* have a value */
        18.           int val_len;
        19.           unsigned int new_val_len;
        20.  
        21.           *val++ = '\0';
        22.           php_url_decode(var, strlen(var));
        23.           val_len = php_url_decode(val, strlen(val));
        24.           val = estrndup(val, val_len);
        25.           if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) {
        26.                php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);
        27.           }
        28.           efree(val);
        29.      } 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數組中, 就包含了如下的成員:

        1. 'name' => 'laruence',
        2. 'career' => array(
        3.      '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(
    2.           'name' => 'laruence',
    3.           'career' => array(
    4.                'yahoo', 'baidu',
    5.           ),

    那麼, 我們今天就重點關注下, 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

未完待續(變數的銷毀過程)…



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.