声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。 http://imsiren.com/archives/601 好久没有写博客了…最近事挺多, 换了工作,又搬了家.. 今天就来说说 我们经常用到的global语句吧.. 我们都知道,在函数体内声明的变量,作用域只是当前函
声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。
http://imsiren.com/archives/601
好久没有写博客了…最近事挺多,
换了工作,又搬了家..
今天就来说说 我们经常用到的global语句吧..
我们都知道,在函数体内声明的变量,作用域只是当前函数体中,一般情况下是访问不到外部声明的变量的.
因为全局变量和局部变量存放在不同的hashtable,
全局变量在symbol_table中,而局部变量则存在active_symbol_table中.
这样就将它们分开了,那 global是怎么实现的呢?
经过简单分析,通过re2c&&yacc定位到 global的token
t_global global_var_list ';'................global_var_list: global_var_list ',' global_var { zend_do_fetch_global_variable(&$3, null, zend_fetch_global_lock tsrmls_cc); } | global_var { zend_do_fetch_global_variable(&$1, null, zend_fetch_global_lock tsrmls_cc); };
重点是在zend_do_fetch_global_variable这个函数中,我们进去看看,
void zend_do_fetch_global_variable(znode * varname,const znode * static_assignment,int fetch_type tsrmls_dc) /* {{{ */ { zend_op * opline; znode lval; znode result; if(varname->op_type == is_const) { if(z_type(varname->u . constant) != is_string) { convert_to_string(&varname->u . constant); } } opline = get_next_op(cg(active_op_array)tsrmls_cc); opline->opcode = zend_fetch_w; /* the default mode must be write, since fetch_simple_variable() is used to define function arguments */ opline->result . op_type = is_var; opline->result . u . ea . type = 0; opline->result . u . var = get_temporary_variable(cg(active_op_array)); opline->op1 = * varname; set_unused(opline->op2); opline->op2 . u . ea . type = fetch_type; result = opline->result; if(varname->op_type == is_const) { zval_copy_ctor(&varname->u . constant); } fetch_simple_variable(&lval,varname,0tsrmls_cc); /* relies on the fact that the default fetch is bp_var_w */ zend_do_assign_ref(null,&lval,&result tsrmls_cc); cg(active_op_array)->opcodes[cg(active_op_array)->last - 1] . result . u . ea . type |= ext_type_unused;}
1:此函数先验证我们获取的变量是否是常量,如果是常量并且不是字符串类型,则就将它转换成string类型.
2:此函数生成一个op , zend_fetch_w
3:释放const
4:fetch_simple_variable会检测是不是auto_global
最重要的地方是 zend_fetch_w
通过计算 可以知道 op的函数是zend_fetch_w_spec_cv_handler
static int zend_fastcall zend_fetch_w_spec_cv_handler(zend_opcode_handler_args){ return zend_fetch_var_address_helper_spec_cv(bp_var_w, zend_opcode_handler_args_passthru);}
zend_fetch_var_address_helper_spec_cv的工作:
1:转换成is_string类型
2:如果是类的静态成员,则通过::获取过来,否则,通过zend_get_target_symbol_table函数返回全局变量symbol_table .
return &eg(symbol_table);
3:通过zend_hash_find 在 target_symbol_table 中查找,target_symbol_table是一个临时hashtable.用来存放 symbol_table的数据.
4: 如果没有找到,则会以写的方式 创建一条数据到target_symbol_table中.这就是,我们为什么通过global一个不存在的变量的时候不出错,并且会创建该变量的原因.
http://imsiren.com/archives/601