深入理解php原理 鸟哥,深入理解PHP原理之Global关键字

转载:http://www.laruence.com/2008/08/24/377.html

闲来无事,就系统的从PHP的词法分析、语法分析、opcodes生成、执行,整个流程,详细的分析了global关键字的实现。

当你在脚本中写下:

的时候,你知道PHP是怎么实现在函数作用域找到全局变量的么?在我前面的文章中(深入理解PHP原理之Opcodes)讲过, PHP的执行,经历了如下几个阶段:

1.Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)

2.Parsing, 将Tokens转换成简单而有意义的表达式

3.Compilation, 将表达式编译成Opocdes

4.Execution, 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。

那么,第一阶段,自然就是Scanning了, 在词法分析阶段,我们的

global $var;

会被解析为:

T_GLOBAL var;

接下来是parsing阶段:

T_GLOBAL var;

yacc经过规则:

statement:

| 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是真正生成opcode的函数:

zend_op *opline;

......

opline->opcode = ZEND_FETCH_W;

opline->result.op_type = IS_VAR;

......

opline->op2.u.EA.type = ZEND_FETCH_GLOBAL_LOCK;

而对于ZEND_FETCH_W的op_handler是:

ZEND_VM_HANDLER(83, ZEND_FETCH_W, CONST|TMP|VAR|CV, ANY)

{

ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, BP_VAR_W);

}

我们来看看zend_fetch_var_adress_helper:

.....

target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), type, varname TSRMLS_CC);

if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) {

switch (type) {

case BP_VAR_R:

case BP_VAR_UNSET:

zend_error(E_NOTICE,"Undefined variable: %s", Z_STRVAL_P(varname));

/* break missing intentionally */

case BP_VAR_IS:

retval = &EG(uninitialized_zval_ptr);

break;

case BP_VAR_RW:

zend_error(E_NOTICE,"Undefined variable: %s", Z_STRVAL_P(varname));

/* break missing intentionally */

case BP_VAR_W: {

zval *new_zval = &EG(uninitialized_zval);

new_zval->refcount++;

zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval);

}

break;

EMPTY_SWITCH_DEFAULT_CASE()

}

}

可以看出,核心就是zend_get_targer_symbol_table这个函数了:

static inline HashTable *zend_get_target_symbol_table(zend_op *opline, temp_variable *Ts, int type, zval *variable TSRMLS_DC)

{

switch (opline->op2.u.EA.type) {

case ZEND_FETCH_LOCAL:

return EG(active_symbol_table);

break;

case ZEND_FETCH_GLOBAL:

case ZEND_FETCH_GLOBAL_LOCK:

return &EG(symbol_table);

break;

case ZEND_FETCH_STATIC:

if (!EG(active_op_array)->static_variables) { ALLOC_HASHTABLE(EG(active_op_array)->static_variables); zend_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); } return EG(active_op_array)->static_variables;

break;

EMPTY_SWITCH_DEFAULT_CASE()

}

return NULL;

}

恩,问题清楚了,也就是说, 如果你global了一个变量,那么Zend就会去全局symbol_table去寻找,如果找不到,就会在全局symbol_table中分配相应的变量。 通过这样的机制,实现了全局变量。   上面是转账鸟哥的一篇博文,最后的源码讲述部分,我补充一下,zend_get_target_symbol_table()这个函数仅仅是获取HashTable,核心逻辑不在这里,是在zend_hash_find()这个方法的判断中,如果该global关键字不在HashTable中定义,由于type为BP_VAR_W(这个宏ZEND_VM_DISPATCH_TO_HELPER_EX中的参数已经表明),就走BP_VAR_W的case分支,该分支中的逻辑才是鸟哥所说的“如果找不到,就会在全局symbol_table中分配相应的变量”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值