版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、PHP中的变量作用域作者:廖宇雷()前言:PHP 中的变量作用域表面上看似简单,但实际上是一个比较复杂的问题。如果能够更进一步的了解 PHP 中变量的作用域,不但能够避免一些奇怪的问题,而且还能利用一些特性来简化程序开发。变量符号表这个东西是我虚构出来的一个表格结构。每一个变量符号表里面保存着当前变量作用域中可用的变量。一个变量符号表的内容可能如左所示。 变量符号表是一个很简单的东西,但 PHP 引擎在执行代码时,需要从变量符号表中查找当前能够使用的变量,以及将初始化的变量添加到变量符号表中。后文简称变量符号表为“符号表”。初始的符号表在 PHP 引擎初始化时,会初始化一个变量符号表,这个符号
2、表称为“初始符号表”,实际上就是 PHP 的全局变量空间。所有的开发者定义的全局变量都保存在其中。 PHP 引擎在初始化任何符号表时,都会将 PHP 内部定义的超级全局变量添加到符号表中。这样,开发者就可以在程序的任何地方使用这些超级全局变量了。 要向符号表添加一个变量非常简单,只要初始化一个变量即可(给变量赋值)。代码示例:PHP 引擎执行到 $my_var = test 时,就会在符号表中添加一个新项目:在上面示例接下来的代码中,就可以使用 $my_var 这个变量了。超级全局变量在 PHP 中,$_GET、$_POST 等一系列全局变量被称为超级全局变量。为什么叫做超级呢?是因为 PHP
3、 引擎在创建一个新的符号表时,总是将这些超级变量添加到符号表中。由于有了这种“特殊待遇”,所以在 .php 文件的任何地方都可以直接使用这些超级全局变量。PHP 的超级全局变量有:$GLOBALS、$_SERVER、$_GET、$_POST、$_COOKIE、$_FILES、$_ENV、$_REQUEST、$_SESSION。局部变量代码示例:可以看到在 my_func() 中输出 $my_var 并不能得到“预期”的结果,同样在 my_func() 函数外输出$local_var 也没有结果。那原因是什么呢?PHP 引擎在执行到调用 my_func() 函数的代码时,执行流程就转到 my_f
4、unc() 函数内部。此时 PHP 引擎要做的第一件事就是为本次对 my_func() 函数的调用创建一个新的符号表。然后将超级全局变量添加到符号表中,并将这个新的符号表当作当前使用的符号表。要理解当前符号表,可以举个例子来说明:你今天要去给大楼的住户抄写水电气的计数,所以你准备了一个本子和一支笔。你先来到一楼,你就在本子上找到一页空白的纸。然后开始挨家挨户的查询计数,并将数据和住户的门牌号一一对应记录下来。你很快抄完了一楼的数据,来到了二楼。这时候你再次选了一页空白的纸,开始记录二楼住户的水电气计数。而这个过程就和 PHP 引擎执行到一个函数内部时要创建一个新符号表一回事。在二楼抄写数据时,
5、你不可能同时看到一楼的数据。因为不同楼层的数据是记录在不同的页面上的。当你位于二楼时,记录二楼数据的页面就是你的当前工作页面。在 PHP 引擎来说,执行流程在一个函数内部时,使用的当前符号表就是进入该函数时创建的符号表。回到我们的代码来。这段代码执行到 $local_var = 123 时,当前使用的符号表(函数内部使用的符号表)中就会添加一个 $local_var (右表):接下来执行 echo $local_var 就理所当然的输出了结果。而 echo $my_var 则因为在当前使用的符号表中找不到名为 $my_var 的变量(这个变量在另一个符号表中),自然不会有输出结果了。my_fu
6、nc() 函数执行完毕后, PHP 引擎就销毁了当前使用的符号表(也就是执行流程进入my_func() 函数时创建的那个新符号表)。并将调用 my_func() 函数之前使用的符号表设置为当前符号表。接下来的 echo $local_var 代码则因为在符号表中找不到 $local_var 变量而没有输出结果。要点:每一次函数(包括对象的方法)调用,都会创建一个新的符号表。并且这个新符号表只在函数(方法)内部有效。函数(方法)执行完毕后,这个新建立的符号表就被销毁了。只要能理解到上面的内容,那么我们就可以很明确的知道在函数(方法)内部定义的变量,是不能在函数(方法)外部被使用的。因为包含这些变
7、量的符号表在函数(方法)执行完毕后就被销毁了。这些在函数(方法)内部定义的变量都称为局部变量,意思就是局部有效。不过局部变量还有一种特殊的类别,那就是静态变量。本文稍后会对局部静态变量做详细阐述。除了函数内部定义的变量,函数的参数也会被添加到函数内的符号表中。函数参数引入的局部变量代码示例:这个 .php 文件的执行结果就不用说了,我们要关注的是 my_func2() 中对 $arg1 这个变量的使用。回顾前面一个小节的内容,我们知道 PHP 引擎在执行流程进入一个函数时会创建一个新的符号表,并把超级全局变量添加到其中。而在 my_func2() 函数中,我们为函数指定了一个名为$arg1 的
8、参数,那么 PHP 引擎还会把函数的参数也添加到符号表中。这样做以后,我们在 my_func2() 函数中就能直接使用 $arg1 变量了。至于我们调用 my_func2() 时传递的参数值,会被复制到 $arg1 变量中。函数内的静态变量除了函数内部定义的变量和函数参数,函数内还有一种变量,那就是静态变量。静态变量有一个很特别的功能,那就是可以在 PHP 引擎执行完毕函数后仍然保留函数内部静态变量的值。代码示例:可以看出,两次调用 my_func3() 并没有导致 $counter 局部变量被重置,而是依次累加。PHP引擎在执行到 my_func3() 时,仍然会建立一个符号表,并将超级全局
9、变量和$arg1参数添加到符号表中。然后根据 static $counter 变量定义,将 $counter 也添加到符号表中。但 PHP 引擎会特别处理 $counter 变量。PHP 引擎会扫描一个专门的静态变量存储区域,检查是否有 my_func3() 的 $counter 变量保存在这里。如果没有,则说明这是第一次调用 my_func3() 函数。那么 PHP 引擎会按照 static $counter = 1 的定义,将 $counter 变量的值初始化为 1,并将 $counter 添加到静态变量独有的保存区域。执行完 my_func3() 后,PHP 引擎会销毁当前的符号表。但由
10、于 $counter 的值保存在静态变量独有的区域,所以 $counter 的值并不会丢失。以后再次执行 my_func3() 时,PHP 引擎会从专门区域将 $counter 变量找出来,添加到当前的符号表中。从而达到不管调用 my_func3() 多少次都不会丢失 $counter 值的效果。说明: PHP4 和 PHP5 对静态变量的内部处理方式不同,而且 PHP5 还有类的静态变量。不过从开发者的角度看,使用上是一样的,所以本文就不详细阐述底层细节了。全局变量虽然 PHP 出于安全考虑,不允许我们定义和 $_GET 一样可在任何位置使用的超级全局变量。但我们仍然可以在程序中使用 glo
11、bal 关键词来定义全局变量。不过 global 的使用有许多晦涩的地方,下面我们从最简单的例子开始。代码示例:执行这个脚本时,$my_global 会被添加到该脚本文件的符号表中。因为我们是通过 PHP 执行该脚本的,所以执行这个脚本时使用的符号表就是初始符号表。在执行到 $my_global = 123 时,会将 $my_global 添加到初始符号表中。接下来对 my_func4() 的调用就会发生有趣的事情了。 my_func4() 中用 global $my_global 表示要将一个全局变量空间的变量添加到当前符号表中。回顾本文最开始的内容,我们就知道初始符号表实际上就是全局变量空
12、间。将初始符号表中的 $my_global 变量添加到 my_func4() 内部使用的符号表后,接下来的 echo 函数就输出了正确的结果。在对比函数 my_func5() 中,没有使用 global $my_global ,所以其中的echo 语句不能输出期望的结果。 我们来看看另一个示例:在前面的叙述中,我把 global 的功能描述为是将全局变量空间的变量添加到当前符号表。而这段示例代码中,我们根本没有在全局变量空间定义 $my_global 这个变量。那这段代码的执行结果是什么呢?结果是否出人意料呢?其实前面对 global 的解释有一些不正确的地方。但是我不想一开始将将 globa
13、l 的复杂特性全端出来,这只会导致读者更难以理解。所以我选择逐步为读者揭示 global 的独特作用。global 实际上是在当前符号表中创建指定全局变量的一个引用。而且 global 还会检查指定的全局变量是否存在,如果不存在则创建一个值为 null 的全局变量。所以 my_func4() 中的 global $my_global 会在全局变量空间创建一个 $my_global 变量,然后在当前符号表中再创建一个该全局变量的引用。通过下面的代码即可证实这一点:可以看到,虽然 my_func4() 里面只有 global $my_global,并没有为 $my_global 赋值。但调用 my
14、_func4()后,全局变量空间(初始符号表)中仍然有了 $my_global 变量。除了用 global 使用全局变量,另一个更方便的途径就是使用 $GLOBALS 超级全局变量。由于 $GLOBALS 超级全局变量可以在程序的任意地方使用,所以比使用 global 来引用全局变量更方便。代码示例:变量作用域的传递熟悉局部变量和全局变量后,我们再来看看变量作用域的传递特性。代码示例:由于我们是首先执行 var_a.php,此时 var_a.php 使用的是初始符号表,所以在 var_a.php 中定义的 $var_a 变量被自动加入到全局变量空间。接下来的 include(var_b.php
15、) 载入并执行了 var_b.php。此时 var_b.php 使用的符号表是哪一个呢?答案很简单,var_b.php 使用的符号表是 var_a.php 当前使用的符号表,既初始符号表。所以var_b.php 中能够正确输出在 var_a.php 定义的 $var_a 变量的值。重点:被 INCLUDE/REQUIRE 的文件使用的符号表是执行 INCLUDE/REQUIRE 语的句代码段使用符号表。为了帮助理解,我们再来看一个示例:在这个例子中,我们是从 var_a.php 的 my_func_a() 中 include 文件 var_b.php 的。所以 var_b.php 使用的符号表
16、就是 my_func_a() 中使用符号表。最后只能正确输出在 my_func_a() 中定义的 $local_var 变量。通过这两个示例,我们可以发现 include/require 载入并执行一个 .php 文件时,PHP 引擎并不会创建新的符号表,而是继承了执行 include/require 语句的代码段当前使用的符号表。这个规则还适用于 eval() 函数。再看看这个更复杂的例子:不过因为调用对象方法时,PHP 引擎会在新建立的符号表中自动添加一个名为 $this 的变量来表示当前对象实例,所以我们在 var_b.php 可以输出这个 $this 变量。只要你明确理解了变量作用域的传递特性,那么很多与下面类似的代码就很好理解了:要注意的是,对于同一个文件,如果被执行的时机不同,那么其使用的符号表也是不同的。例如通过 PHP 直接运行 a.php 和通过 b.php 中的一个函数 include 来执行 a.p
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 关于劳动合同协议书范文
- 线上工程服务合同范例
- 未婚生子分手协议书协议书范本
- 管材销售代加工合同范例
- 住房节能改造合同范例
- 策展人合同范例
- 梯维保合同范例
- 房屋工程修缮合同范例
- 简易商业租赁合同模板
- 债务方协议书
- 高三励志写给高三的自己
- GB/T 16453.3-2008水土保持综合治理技术规范沟壑治理技术
- GA 306.1-2007阻燃及耐火电缆塑料绝缘阻燃及耐火电缆分级和要求第1部分:阻燃电缆
- 课件:第三章 社会工作项目的策划(《社会工作项目策划与评估》课程)
- 私募基金与公募基金介绍课件
- 康复医学课件-第二章 康复评定
- 教师招聘试讲评价表
- 二 年级上册美术课件-《雪花飘飘》|北京课改版 (共25张PPT)
- 机械类复试面试问题汇总(200多道题)
- 新中国十大元帅!课件
- 地籍技术设计书
评论
0/150
提交评论