PHP内核探索:变量作用域

变量的作用域是变量的一个作用范围
服务器君一共花费了168.698 ms进行了4次数据库查询,努力地为您提供了这个页面。
试试阅读模式?希望听取您的建议

变量的作用域是变量的一个作用范围,在这个范围内变量为可见的,即可以访问该变量的代码区域, 相反,如果不在这个范围内,变量是不可见的,无法被调用。 (全局变量可以将作用范围看作为整个程序) 如下面的例子:(会输出什么样的结果呢?)

<?php
    $foo = 'nowamagic';
    function variable_scope(){
        $foo = 'foo';
        print $foo ;
        print $bar ;
    }
?>

由此可见,变量的作用域是一个很基础的概念,在变量的实现中比较重要。

全局变量与局部变量

变量按作用域类型分为:全局变量和局部变量。全局变量是在整个程序中任何地方随意调用的变量, 在PHP中,全局变量的“全局化”使用gloal语句来实现。 相对于全局变量,局部变量的作用域是程序中的部分代码(如函数中),而不是程序的全部。

变量的作用域与变量的生命周期有一定的联系, 如在一个函数中定义的变量, 这个变量的作用域从变量声明的时候开始到这个函数结束的时候。 这种变量我们称之为局部变量。它的生命周期开始于函数开始,结束于函数的调用完成之时。

变量的作用域决定其生命周期吗?程序运行到变量作用域范围之外,就会将变量进行销毁吗?

对于不同作用域的变量,如果存在冲突情况,就像上面的例子中,全局变量中有一个名为$bar的变量, 在局部变量中也存在一个名为$bar的变量, 此时如何区分呢?

对于全局变量,ZEND内核有一个_zend_executor_globals结构,该结构中的symbol_table就是全局符号表, 其中保存了在顶层作用域中的变量。同样,函数或者对象的方法在被调用时会创建active_symbol_table来保存局部变量。 当程序在顶层中使用某个变量时,ZE就会在symbol_table中进行遍历, 同理,如果程序运行于某个函数中,Zend内核会遍历查询与其对应的active_symbol_table, 而每个函数的active_symbol_table是相对独立的,由此而实现的作用域的独立。

展开来看,如果我们调用的一个函数中的变量,ZE使用_zend_execute_data来存储 某个单独的op_array(每个函数都会生成单独的op_array)执行过程中所需要的信息,它的结构如下:

struct _zend_execute_data {
    struct _zend_op *opline;
    zend_function_state function_state;
    zend_function *fbc; /* Function Being Called */
    zend_class_entry *called_scope;
    zend_op_array *op_array;
    zval *object;
    union _temp_variable *Ts;
    zval ***CVs;
    HashTable *symbol_table;
    struct _zend_execute_data *prev_execute_data;
    zval *old_error_reporting;
    zend_bool nested;
    zval **original_return_value;
    zend_class_entry *current_scope;
    zend_class_entry *current_called_scope;
    zval *current_this;
    zval *current_object;
    struct _zend_op *call_opline;
};

函数中的局部变量就存储在_zend_execute_data的symbol_table中,在执行当前函数的op_array时, 全局zend_executor_globals中的*active_symbol_table会指向当前_zend_execute_data中的*symbol_table。 因为每个函数调用开始时都会重新初始化EG(active_symbol_table)为NULL, 在这个函数的所有opcode的执行过程中这个全局变量会一直存在,并且所有的局部变量修改都是在它上面操作完成的,如前面的赋值操作等。 而此时,其他函数中的symbol_table会存放在栈中,将当前函数执行完并返回时,程序会将之前保存的zend_execute_data恢复, 从而其他函数中的变量也就不会被找到,局部变量的作用域就是以这种方式来实现的。 相关操作在 Zend/zend_vm_execute.h 文件中定义的execute函数中一目了然,如下所示代码:

zend_vm_enter:
/* Initialize execute_data */
execute_data = (zend_execute_data *)zend_vm_stack_alloc(
    sizeof(zend_execute_data) +
    sizeof(zval**) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2) +
    sizeof(temp_variable) * op_array->T TSRMLS_CC);
 
EX(symbol_table) = EG(active_symbol_table);
EX(prev_execute_data) = EG(current_execute_data);
EG(current_execute_data) = execute_data;

所以,变量的作用域是使用不同的符号表来实现的,于是顶层的全局变量在函数内部使用时, 需要先使用global语句来将变量“挪”到函数独立的*active_symbol_table中, 即变量的跨域操作。

在PHP的源码中,EX宏经常出现,它的作用是获取结构体zend_execute_data的字段值,它的实现是:#define EX(element) execute_data->element

延伸阅读

此文章所在专题列表如下:

  1. PHP内核探索:从SAPI接口开始
  2. PHP内核探索:一次请求的开始与结束
  3. PHP内核探索:一次请求生命周期
  4. PHP内核探索:单进程SAPI生命周期
  5. PHP内核探索:多进程/线程的SAPI生命周期
  6. PHP内核探索:Zend引擎
  7. PHP内核探索:再次探讨SAPI
  8. PHP内核探索:Apache模块介绍
  9. PHP内核探索:通过mod_php5支持PHP
  10. PHP内核探索:Apache运行与钩子函数
  11. PHP内核探索:嵌入式PHP
  12. PHP内核探索:PHP的FastCGI
  13. PHP内核探索:如何执行PHP脚本
  14. PHP内核探索:PHP脚本的执行细节
  15. PHP内核探索:操作码OpCode
  16. PHP内核探索:PHP里的opcode
  17. PHP内核探索:解释器的执行过程
  18. PHP内核探索:变量概述
  19. PHP内核探索:变量存储与类型
  20. PHP内核探索:PHP中的哈希表
  21. PHP内核探索:理解Zend里的哈希表
  22. PHP内核探索:PHP哈希算法设计
  23. PHP内核探索:翻译一篇HashTables文章
  24. PHP内核探索:哈希碰撞攻击是什么?
  25. PHP内核探索:常量的实现
  26. PHP内核探索:变量的存储
  27. PHP内核探索:变量的类型
  28. PHP内核探索:变量的值操作
  29. PHP内核探索:变量的创建
  30. PHP内核探索:预定义变量
  31. PHP内核探索:变量的检索
  32. PHP内核探索:变量的类型转换
  33. PHP内核探索:弱类型变量的实现
  34. PHP内核探索:静态变量的实现
  35. PHP内核探索:变量类型提示
  36. PHP内核探索:变量的生命周期
  37. PHP内核探索:变量赋值与销毁
  38. PHP内核探索:变量作用域
  39. PHP内核探索:诡异的变量名
  40. PHP内核探索:变量的value和type存储
  41. PHP内核探索:全局变量Global
  42. PHP内核探索:变量类型的转换
  43. PHP内核探索:内存管理开篇
  44. PHP内核探索:Zend内存管理器
  45. PHP内核探索:PHP的内存管理
  46. PHP内核探索:内存的申请与销毁
  47. PHP内核探索:引用计数与写时复制
  48. PHP内核探索:PHP5.3的垃圾回收机制
  49. PHP内核探索:内存管理中的cache
  50. PHP内核探索:写时复制COW机制
  51. PHP内核探索:数组与链表
  52. PHP内核探索:使用哈希表API
  53. PHP内核探索:数组操作
  54. PHP内核探索:数组源码分析
  55. PHP内核探索:函数的分类
  56. PHP内核探索:函数的内部结构
  57. PHP内核探索:函数结构转换
  58. PHP内核探索:定义函数的过程
  59. PHP内核探索:函数的参数
  60. PHP内核探索:zend_parse_parameters函数
  61. PHP内核探索:函数返回值
  62. PHP内核探索:形参return value
  63. PHP内核探索:函数调用与执行
  64. PHP内核探索:引用与函数执行
  65. PHP内核探索:匿名函数及闭包
  66. PHP内核探索:面向对象开篇
  67. PHP内核探索:类的结构和实现
  68. PHP内核探索:类的成员变量
  69. PHP内核探索:类的成员方法
  70. PHP内核探索:类的原型zend_class_entry
  71. PHP内核探索:类的定义
  72. PHP内核探索:访问控制
  73. PHP内核探索:继承,多态与抽象类
  74. PHP内核探索:魔术函数与延迟绑定
  75. PHP内核探索:保留类与特殊类
  76. PHP内核探索:对象
  77. PHP内核探索:创建对象实例
  78. PHP内核探索:对象属性读写
  79. PHP内核探索:命名空间
  80. PHP内核探索:定义接口
  81. PHP内核探索:继承与实现接口
  82. PHP内核探索:资源resource类型
  83. PHP内核探索:Zend虚拟机
  84. PHP内核探索:虚拟机的词法解析
  85. PHP内核探索:虚拟机的语法分析
  86. PHP内核探索:中间代码opcode的执行
  87. PHP内核探索:代码的加密与解密
  88. PHP内核探索:zend_execute的具体执行过程
  89. PHP内核探索:变量的引用与计数规则
  90. PHP内核探索:新垃圾回收机制说明

本文地址:http://www.nowamagic.net/librarys/veda/detail/1420,欢迎访问原出处。

不打个分吗?

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/1420

如果你认为这篇文章值得更多人阅读,欢迎使用下面的分享功能。
小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏

大家都在看

阅读一百本计算机著作吧,少年

很多人觉得自己技术进步很慢,学习效率低,我觉得一个重要原因是看的书少了。多少是多呢?起码得看3、4、5、6米吧。给个具体的数量,那就100本书吧。很多人知识结构不好而且不系统,因为在特定领域有一个足够量的知识量+足够良好的知识结构,系统化以后就足以应对大量未曾遇到过的问题。

奉劝自学者:构建特定领域的知识结构体系的路径中再也没有比学习该专业的专业课程更好的了。如果我的知识结构体系足以囊括面试官的大部分甚至吞并他的知识结构体系的话,读到他言语中的一个词我们就已经知道他要表达什么,我们可以让他坐“上位”毕竟他是面试官,但是在知识结构体系以及心理上我们就居高临下。

所以,阅读一百本计算机著作吧,少年!

《重来:更为简单有效的商业思维》 贾森•弗里德(Jason Fried) (作者), 大卫•汉森(David Heinemeier Hansson) (作者), Mike Rohde (插图作者), 李瑜偲 (译者)

这本书呈现的是一种更好、更简单的经商成功之道。读完这本书,你就会明白为什么计划实际上百害而无一益,为什么你不需要外界投资人,为什么将竞争视而不见反倒会发展得更好。事实是你所需要的比你想象的少得多。你不必成为工作狂,你不必大量招兵买马,你不必把时间浪费在案头工作和会议上,你甚至不必拥有一间办公室。所有这些都仅仅是借口!

更多计算机宝库...