深入理解PHP原理之Global关键字
发布日期:2021-10-05 13:28:26
浏览次数:2
分类:技术文章
本文共 3342 字,大约阅读时间需要 11 分钟。
转载:
闲来无事,就系统的从PHP的词法分析、语法分析、opcodes生成、执行,整个流程,详细的分析了global关键字的实现。 当你在脚本中写下:的时候,你知道PHP是怎么实现在函数作用域找到全局变量的么?在我前面的文章中(深入理解PHP原理之Opcodes)讲过, PHP的执行,经历了如下几个阶段:
1. Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)2. Parsing, 将Tokens转换成简单而有意义的表达式3. Compilation, 将表达式编译成Opocdes4. 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中分配相应的变量”。转载地址:https://blog.csdn.net/lml200701158/article/details/52337145 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
关注你微信了!
[***.104.42.241]2024年04月16日 01时40分51秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
textarea在光标后追加内容,并将换行符替换成br标签
2019-04-25
kafka客户端脚本windows版
2019-04-25
zookeeper基础教程
2019-04-25
zookeeper单机版安装教程
2019-04-25
zookeeper集群版安装教程
2019-04-25
Spring @Cacheable当返回值为null时报错解决方案
2019-04-25
小数在计算机中如何存储?
2019-04-25
什么是二分查找、插值查找、斐波那契查找和索引查找?
2019-04-25
什么是二叉查找树,有什么优势?
2019-04-25
教你玩转二叉查找树的结点插入和删除操作
2019-04-25
下次再让你讲平衡二叉树,可别说不会了
2019-04-25
什么是B-树、B树、B+树、B*树?
2019-04-25
B树结点的插入删除操作
2019-04-25
String s=new String(“abc“)创建了几个对象?
2019-04-25
【干货】Linux 网卡绑定的相关知识和技巧
2019-04-25
学习笔记2021-01-13
2019-04-25
soul源码学习-20210114
2019-04-25
编程语言介绍
2019-04-25
JVM 基础知识
2019-04-25
Java字节码(一)
2019-04-25