global语句的作用是定义全局变量,例如如果想在函数内访问全局作用域内的变量则可以通过global声明来定义。

下面从语法解释开始分析。

1. 词法解析

查看 Zend/zend_language_scanner.l文件,搜索 global关键字。我们可以找到如下代码:

<ST_IN_SCRIPTING>"global" {
return T_GLOBAL;
}

2. 语法解析

在词法解析完后,获得了token,此时通过这个token,我们去Zend/zend_language_parser.y文件中查找。找到相关代码如下:

|   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); }
;

上面代码中的$3是指global_var(如果不清楚yacc的语法,可以查阅yacc入门类的文章。)

从上面的代码可以知道,对于全局变量的声明调用的是zend_do_fetch_global_variable函数,查找此函数的实现在Zend/zend_compile.c文件。

void zend_do_fetch_global_variable(znode *varname, const znode *static_assignment, int fetch_type TSRMLS_DC) 
{
        ...//省略
        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;
 
        ... // 省略
        fetch_simple_variable(&lval, varname, 0 TSRMLS_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;
}
/* }}} */

上面的代码确认了opcode为ZEND_FETCH_W外,还执行了zend_do_assign_ref函数。zend_do_assign_ref函数的实现如下:

void zend_do_assign_ref(znode *result, const znode *lvar, const znode *rvar TSRMLS_DC) /* {{{ */
{
        zend_op *opline;
 
       ... //省略
 
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
        opline->opcode = ZEND_ASSIGN_REF;
       ...//省略
        if (result) {
                opline->result.op_type = IS_VAR;
                opline->result.u.EA.type = 0;
                opline->result.u.var = get_temporary_variable(CG(active_op_array));
                *result = opline->result;
        } else {
                /* SET_UNUSED(opline->result); */
                opline->result.u.EA.type |= EXT_TYPE_UNUSED;
        }
        opline->op1 = *lvar;
        opline->op2 = *rvar;
}

从上面的zend_do_fetch_global_variable函数和zend_do_assign_ref函数的实现可以看出, 使用global声明一个全局变量后,其执行了两步操作,ZEND_FETCH_W和ZEND_ASSIGN_REF。

3. 生成并执行中间代码

我们看下ZEND_FETCH_W的最后执行。从代码中我们可以知道:

  • ZEND_FETCH_W = 83
  • op->op1.op_type = 4
  • op->op2.op_type = 0

而计算最后调用的方法在代码中的体现为:

zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + zend_vm_decode[op->op2.op_type]];

计算,最后调用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中调用如下代码获取符号表

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

在zend_get_target_symbol_table函数的实现如下:

static inline HashTable *zend_get_target_symbol_table(const zend_op *opline, const temp_variable *Ts, int type, const zval *variable TSRMLS_DC)
{
        switch (opline->op2.u.EA.type) {
                ... //  省略
                case ZEND_FETCH_GLOBAL:
                case ZEND_FETCH_GLOBAL_LOCK:
                        return &EG(symbol_table);
                        break;
               ...  //  省略
        }
        return NULL;
}

在前面语法分析过程中,程序传递的参数是 ZEND_FETCH_GLOBAL_LOCK,于是如上所示。我们取&EG(symbol_table);的值。这也是全局变量的存放位置。

如上就是整个global的解析过程。

漫谈php全局变量Global的更多相关文章

  1. php中全局变量global和超全局变量$GLOBALS

    php中全局变量global和超全局变量$GLOBALS 1.global Global的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面,包括include或require ...

  2. PHP中的全局变量global和$GLOBALS的区别

    1.global Global的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面,包括include或require的所有文件. 但是在函数体内定义的global变量,函数体 ...

  3. python 局部变量和全局变量 global

    当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的.这称为变量的 作用域 .所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开 ...

  4. CodeIgniter 定义“全局变量-global variable”,可以在所有controller,model和view中使用

    本文抄自http://www.cnblogs.com/webu/archive/2012/11/20/2779999.html 第一次正儿八经用CodeIgniter框架做项目,结果不会定义全局变量, ...

  5. Python局部变量和全局变量global

    当你在函数定义声明变量的时候,它们与函数外具有相同名称的其它变量没有任何关系,即变量名称对于函数来说是 局部  的.这称为变量的 作用域 .所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开 ...

  6. 关于PHP中的全局变量global和$GLOBALS的不同区分

    1.global Global的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面,包括include或require的所有文件. 但是在函数体内定义的global变量,函数体 ...

  7. PHP中全局变量global和$GLOBALS[]的区别分析

    $GLOBALS['var']是外部的全局变量本身,global $var是外部$var的同名引用或者指针     一.举例比较 例一: 复制代码 代码如下: <?php $var1 = 1; ...

  8. php 中全局变量global 的使用

    简介 即使开发一个新的大型PHP程序,你也不可避免的要使用到全局数据,因为有些数据是需要用到你的代码的不同部分的.一些常见的全局数据有:程序设定类.数 据库连接类.用户资料等等.有很多方法能够使这些数 ...

  9. 【PHP】- 全局变量global和$GLOBALS的区别

    1.global global关键字的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面,包括include或require的所有文件. 但是在函数体内定义的global变量, ...

随机推荐

  1. jetty-distribution-7.6.x 部署

    (1)启动 jetty 命令:java - jar start.jar 需要注意2个事项:必须使用JDK来运行jetty:启动是需要读取 start.ini 的配置信息. (2)第一个注意事项只要保证 ...

  2. MyBatis(3.2.3) - One-to-one mapping using nested ResultMap

    We can get Student along with the Address details using a nested ResultMap as follows: <resultMap ...

  3. 【WebKit】---WebKit的CSS扩展(WebKit是私有属性)

    1.-webkit-touch-callout 当你触摸并按住触摸目标时候,禁止或显示系统默认菜单.在iOS上,当你触摸并按住触摸的目标,比如一个链接,Safari浏览器将显示链接有关的系统默认菜单. ...

  4. C#保存上传来的图片示例代码

    保存上传图片的方法有很多,在接下来的文章中为大家详细介绍下使用C#是如何做到的,感兴趣的朋友不要错过 复制代码代码如下: [HttpPost]  public string UploadImage() ...

  5. 面试之SQL(1)--选出选课数量>=2的学号

    ID      Course 1 AA 1 BB 2 AA 2 BB 2 CC 3 AA 3 BB 3 CC 3 DD 4 AA NULL NULL 选出选课数量>=2的学号 selectdis ...

  6. JQGrid各种参数详解API(转载)

    下面是转自其他人blog的一个学习资料,与其说是学习资料,说成查询帮助文档更加合适. jqGrid学习之 ------------- 安装 jqGrid安装很简单,只需把相应的css.js文件加入到页 ...

  7. Javascript之三种按钮点击事件

    学习Javascript必须要先掌握基本的事件方法和语法,这些都是我们学过的也是最基本的.以前忘了总结,所以现在回顾,综合地总结一下,温故而知新. Javascript有三种按钮点击事件,分别为ale ...

  8. sql还原数据库时候,遇到数据库被占用的解决情况

    最近上班时候,经常要做数据库还原,时常遇到数据被占用的情况, 执行一句sql语句就可以解决, ALTER DATABASE dbname SET OFFLINE WITH ROLLBACK IMMED ...

  9. JQuery中操作表单和表格

    一:表单应用 1.HTML中的表单大致由三部分组成 (1).表单便签:包含处理表单数据所用的服务端程序URL,以及数据提交到服务器的方法. (2).表单域:包含文本框.密码框.隐藏域.多行文本框.复选 ...

  10. JAVA UDP网络编程学习笔记

    一.UDP网络编程概述 采用TCP协议通信时,客户端的Socket必须先与服务器建立连接,连接建立成功后,服务器端也会持有客户端连接的Socket,客户端的Socket与服务器端的Socket是对应的 ...