• php 全局变量


    描述

    PHP中把定义在函数、类之外的变量称之为全局变量,也就是定义在主脚本中的变量,这些变量可以在函数、成员方法中通过global关键字引入使用。

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

    存储

    全局变量在整个请求执行期间始终存在,它们保存在EG(symbol_table)中,也就是全局变量符号表,与静态变量的存储一样,这也是一个哈希表,主脚本(或include、require)在zend_execute_ex执行开始之前会把当前作用域下的所有局部变量添加到EG(symbol_table)

    zend_vm_execute.h中,i_init_execute_data()这个函数中会把局部变量插入到EG(symbol_table):

    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 }

    注意局部变量通过偏移量来访问,而不是变量名

    从上面的过程可以很直观的看到,在执行前遍历局部变量,然后插入EG(symbol_table),EG(symbol_table)中的value直接指向局部变量的zval,示例经过这一步的处理之后(此时局部变量只是分配了zval,但还未初始化,所以是IS_UNDEF):

    访问

    与静态变量的访问一样,全局变量也是将原来的值转换为引用,然后在global导入的作用域内创建一个局部变量指向该引用:

    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 }
    for remember
  • 相关阅读:
    转 Python学习(九)
    转 Python学习(八)
    转 Python学习(七)
    转 Python学习(六)
    转 Python学习(五)
    转 Python学习(四)
    转Python学习(三)
    转Python学习(一)
    面向对象第三章(向上造型、重写、重载)
    面向对象第一章(成员变量、局部变量、重载)
  • 原文地址:https://www.cnblogs.com/dearmrli/p/8608521.html
Copyright © 2020-2023  润新知