php 全局變量

描述app

PHP中把定義在函數、類以外的變量稱之爲全局變量,也就是定義在主腳本中的變量,這些變量能夠在函數、成員方法中經過global關鍵字引入使用。函數

1 function test() {
2     global $id;
3     $id++;
4 }
5 
6 $id = 1;
7 test();
8 echo $id;

存儲ui

全局變量在整個請求執行期間始終存在,它們保存在EG(symbol_table)中,也就是全局變量符號表,與靜態變量的存儲同樣,這也是一個哈希表,主腳本(或include、require)在zend_execute_ex執行開始以前會把當前做用域下的全部局部變量添加到EG(symbol_table)spa

zend_vm_execute.h中,i_init_execute_data()這個函數中會把局部變量插入到EG(symbol_table):code

1 ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value)
2 {
3     ...
4     i_init_execute_data(execute_data, op_array, return_value);
5     zend_execute_ex(execute_data);
6     ...
7 }
i_init_execute_data會把局部變量插入到EG(symbol_table),定義在zend_execute.c
 1 static zend_always_inline void i_init_code_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
 2 {
 3     ZEND_ASSERT(EX(func) == (zend_function*)op_array);
 4 
 5     EX(opline) = op_array->opcodes;
 6     EX(call) = NULL;
 7     EX(return_value) = return_value;
 8 
 9     zend_attach_symbol_table(execute_data);
10 
11     if (!op_array->run_time_cache) {
12         op_array->run_time_cache = emalloc(op_array->cache_size);
13         memset(op_array->run_time_cache, 0, op_array->cache_size);
14     }
15     EX_LOAD_RUN_TIME_CACHE(op_array);
16     EX_LOAD_LITERALS(op_array);
17 
18     EG(current_execute_data) = execute_data;
19 }
zend_attach_symbol_table 把局部變量插入到EG(symbol_table),定義在zend_execute_API.c中
 1 ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ */
 2 {
 3     zend_op_array *op_array = &execute_data->func->op_array;
 4     HashTable *ht = execute_data->symbol_table; //全局變量符號表
 5 
 6     /* copy real values from symbol table into CV slots and create
 7        INDIRECT references to CV in symbol table  */
 8     if (EXPECTED(op_array->last_var)) {
 9         zend_string **str = op_array->vars; //局部變量
10         zend_string **end = str + op_array->last_var;//最後一個局部變量的位置
11         zval *var = EX_VAR_NUM(0);
12 
13         do {
14             zval *zv = zend_hash_find(ht, *str);
15 
16             if (zv) {
17                 if (Z_TYPE_P(zv) == IS_INDIRECT) {
18                     zval *val = Z_INDIRECT_P(zv);
19 
20                     ZVAL_COPY_VALUE(var, val);
21                 } else {
22                     ZVAL_COPY_VALUE(var, zv);
23                 }
24             } else {
25                 ZVAL_UNDEF(var);
26                 zv = zend_hash_add_new(ht, *str, var);//添加到全局變量符號表
27             }
28             ZVAL_INDIRECT(zv, var);
29             str++;//指向下一個局部變量
30             var++;
31         } while (str != end);
32     }
33 }

注意局部變量經過偏移量來訪問,而不是變量名blog

從上面的過程能夠很直觀的看到,在執行前遍歷局部變量,而後插入EG(symbol_table),EG(symbol_table)中的value直接指向局部變量的zval,示例通過這一步的處理以後(此時局部變量只是分配了zval,但還未初始化,因此是IS_UNDEF):element

訪問作用域

與靜態變量的訪問同樣,全局變量也是將原來的值轉換爲引用,而後在global導入的做用域內建立一個局部變量指向該引用:string

1 global $id; // 至關於:$id = & EG(symbol_table)["id"];
銷燬
局部變量若是沒有手動銷燬,那麼在函數執行結束時會將它們銷燬,而全局變量則是在整個請求結束時纔會銷燬,即便是咱們直接在PHP腳本中定義在函數外的那些變量。
 1 void shutdown_destructors(void)
 2 {
 3     if (CG(unclean_shutdown)) {
 4         EG(symbol_table).pDestructor = zend_unclean_zval_ptr_dtor;
 5     }
 6     zend_try {
 7         uint32_t symbols;
 8         do {
 9             symbols = zend_hash_num_elements(&EG(symbol_table));
10             //銷燬
11             zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t) zval_call_destructor);
12         } while (symbols != zend_hash_num_elements(&EG(symbol_table)));
13     }
14     ...
15 }
相關文章
相關標籤/搜索