当前位置:  开发笔记 > 编程语言 > 正文

PHP源码分析之Global关键字

闲来无事,就系统的从PHP的词法分析,语法分析,opcodes生成,执行,整个流程,详细的分析了global关键字的实现。当你在脚本中写下:<?php$var="laruence";functionsample(){globa...">

 

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

  当你在脚本中写下:

 

  

  $var = "laruence";

  function sample(){

  global $var;

  }

  ?>

 

  的时候,你知道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 &#39;;&#39;

  ....

  global_var_list:

  global_var_list &#39;,&#39; 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 (!target_symbol_table) { ZEND_VM_NEXT_OPCODE(); }*/ 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中分配相应的变量。

  通过这样的机制,实现了全局变量。


推荐阅读
  • 《Offer冲刺:剑指Offer学习心得与经验分享》 ... [详细]
  • Norton Partition Magic 中 PHP 函数 error_reporting(E_ALL ^ E_NOTICE) 的详细解析与应用
    在 Windows 环境下,通过具体示例分析了 `Norton Partition Magic` 中 `PHP` 函数 `error_reporting(E_ALL ^ E_NOTICE)` 的详细解析与应用。该函数用于控制错误报告级别,例如在从 PHP 4.3.0 升级到 4.3.1 后,程序出现多处错误的原因及解决方法。本文深入探讨了错误报告配置对程序稳定性的影响,并提供了实用的调试技巧。 ... [详细]
  • 大数据应用实例:电视收视率分析企业项目实操第二篇
    本文继续探讨大数据在电视收视率分析中的应用,详细介绍了如何在CentOS系统中进行防火墙管理。针对CentOS 6.5及更早版本,提供了具体的命令操作步骤,包括停止防火墙服务和禁用防火墙启动。此外,还深入讨论了这些操作对数据传输和系统安全的影响,为实际项目实施提供了宝贵的技术参考。 ... [详细]
  • 如何在华为手机上配置应用后台运行模式? ... [详细]
  • 石大师教你解决电脑黑屏问题:专业重装系统方法详解
    石大师教你解决电脑黑屏问题:专业重装系统方法详解 ... [详细]
  • Spring Security 认证模块的项目构建与初始化
    本文详细介绍了如何构建和初始化Spring Security认证模块的项目。首先,通过创建一个分布式Maven聚合工程,该工程包含四个模块,分别为core、browser(用于演示)、app等,以构成完整的SeehopeSecurity项目。在项目构建过程中,还涉及日志生成机制,确保能够输出关键信息,便于调试和监控。 ... [详细]
  • Navicat for MariaDB 15:可视化数据洞察与智能图表功能详解
    Navicat for MariaDB 15:可视化数据洞察与智能图表功能详解 ... [详细]
  • 轻食餐饮行业进阶指南:从初学者到实现可持续运营
    根据美团外卖的数据,2020年下半年轻食外卖订单量同比增长了50%,同时在线轻食商家的数量也显著增加。本文旨在为轻食餐饮行业的初学者提供全面的进阶指南,从市场趋势分析、产品开发到营销策略,帮助创业者实现可持续运营。通过深入探讨行业动态和成功案例,本文将助力轻食餐饮企业在竞争激烈的市场中脱颖而出。 ... [详细]
  • 如何在IDEA中安装和配置反编译插件以提高代码审查效率
    在 IntelliJ IDEA 中提升代码审查效率的一种方法是安装和配置反编译插件。首先,进入 IDEA 的设置界面,然后导航到插件管理部分。接下来,搜索 "ideaJad" 插件并进行安装。安装完成后,重启 IDEA 以确保插件生效。这将帮助你在审查二进制文件时更加高效地查看源代码。 ... [详细]
  • 本周的工作与生活经历颇为波折。原本决心坚决要与妻子离婚,但令人意外的是,她突然提出和好。这种突如其来的变化让人感到困惑和不解,不知是自己的态度过于软弱还是她的行为背后有其他原因。尽管她再次表示愿意修复关系,但她的冷漠和不关心依旧让我感到失望和无奈。 ... [详细]
  • 织梦系统多条件联动筛选功能详细教程及删除操作指南
    多条件联动筛选功能广泛应用于图片展示、装修设计、机械设备和在线商城等场景,通常筛选条件应聚焦于用户最关心的要素,而非涵盖所有可能的选项。在DedeCMS中,多条件筛选的PHP开发并未内置删除已选条件的功能,但通过理解PHP筛选与JS筛选的不同机制,实现这一功能相对简单且易于操作。 ... [详细]
  • Git基础操作指南:掌握必备技能
    掌握 Git 基础操作是每个开发者必备的技能。本文详细介绍了 Git 的基本命令和使用方法,包括初始化仓库、配置用户信息、添加文件、提交更改以及查看版本历史等关键步骤。通过这些操作,读者可以快速上手并高效管理代码版本。例如,使用 `git config --global user.name` 和 `git config --global user.email` 来设置全局用户名和邮箱,确保每次提交时都能正确标识提交者信息。 ... [详细]
  • 优化后的标题:数据网格视图(DataGridView)在应用程序中的高效应用与优化策略
    在应用程序中,数据网格视图(DataGridView)的高效应用与优化策略至关重要。本文探讨了多种优化方法,包括但不限于:1)通过合理的数据绑定提升性能;2)利用虚拟模式处理大量数据,减少内存占用;3)在格式化单元格内容时,推荐使用CellParsing事件,以确保数据的准确性和一致性。此外,还介绍了如何通过自定义列类型和优化渲染过程,进一步提升用户体验和系统响应速度。 ... [详细]
  • QQ坦白说功能详解:身份标签全解析与应用指南
    如今,许多用户正在体验手机QQ的坦白说功能,许多人对这一功能中的身份标签选择感到好奇。本文将详细介绍可用的身份标签及其具体应用,帮助大家更好地理解和使用坦白说功能。如果你对坦白说还不熟悉,欢迎点击链接了解更多详细信息。 ... [详细]
  • 为了在Fragment中直接调用Activity的方法,可以通过定义一个接口并让Activity实现该接口来实现。具体步骤包括:首先在Fragment中声明一个接口,并在Activity中实现该接口。接着,在Fragment中通过类型转换检查Activity是否实现了该接口,如果实现了则调用相应的方法。这种方法不仅提高了代码的解耦性,还增强了模块间的通信效率。此外,还可以通过ViewModel或LiveData等现代Android架构组件进一步优化这一过程,以实现更加高效和可靠的通信机制。 ... [详细]
author-avatar
手机用户2502908275
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有