浅析php变量作用域的一些问题


Posted in PHP onAugust 08, 2013

昨晚就与到这么一个问题,是全局变量在函数中的问题。今天搜索了一下,发现一篇相当不错的文章,讲了php中的变量作用域。是一位网友翻译的在这贴一下:

变量范围
变量的范围即它定义的上下文背景(译者:说白了,也就是它的生效范围)。大部分的 PHP 变量只有一个单独的范围。这个单独的范围跨度同样包含了 include 和 require 引入的文件。范例:

<?php
$a = 1;
include "b.inc";
?> 

这里变量 $a 将会在包含文件 b.inc 中生效。但是,在用户自定义函数中,一个局部函数范围将被引入。任何用于函数内部的变量按缺省情况将被限制在局部函数范围内。范例:
<?php
$a = 1; /* global scope */
function Test()
{
   echo $a; /* reference to local scope variable */
}
Test();
?> 

这个脚本不会有任何输出,因为 echo 语句引用了一个局部版本的变量 $a,而且在这个范围内,它并没有被赋值。你可能注意到 PHP 的全局变量和 C 语言有一点点不同,在 C 语言中,全局变量在函数中自动生效,除非被局部变量覆盖。这可能引起一些问题,有些人可能漫不经心的改变一个全局变量。PHP 中全局变量在函数中使用时必须申明为全局。

The global keyword
首先,一个使用 global 的例子:
例子 12-1. 使用 global

<?php
$a = 1;
$b = 2;
function Sum()
{
   global $a, $b;
   $b = $a + $b;
}
Sum();
echo $b;
?> 

以上脚本的输出将是 "3"。在函数中申明了全局变量 $a 和 $b,任何变量的所有引用变量都会指向到全局变量。对于一个函数能够申明的全局变量的最大个数,PHP 没有限制。

在全局范围内访问变量的第二个办法,是用特殊的 PHP 自定义 $GLOBALS 数组。前面的例子可以写成:

例子 12-2. 使用 $GLOBALS 替代 global

<?php
$a = 1;
$b = 2;
function Sum()
{
   $GLOBALS["b"] = $GLOBALS["a"] + $GLOBALS["b"];
}
Sum();
echo $b;
?> 

在 $GLOBALS 数组中,每一个变量为一个元素,键名对应变量名,值变量的内容。$GLOBALS 之所以在全局范围内存在,是因为 $GLOBALS 是一个超全局变量。以下范例显示了超全局变量的用处:

例子 12-3. 演示超全局变量和作用域的例子

<?php
function test_global()
{
   // 大多数的预定义变量并不 "super",它们需要用 'global' 关键字来使它们在函数的本地区域中有效。
   global $HTTP_POST_VARS;
   print $HTTP_POST_VARS['name'];
   // Superglobals 在任何范围内都有效,它们并不需要 'global' 声明。Superglobals 是在 PHP 4.1.0 引入的。
   print $_POST['name'];
}
?> 

使用静态变量
变量范围的另一个重要特性是静态变量(static variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子:

例子 12-4. 演示需要静态变量的例子

<?php
function Test ()
{
   $a = 0;
   echo $a;
   $a++;
}
?> 

本函数没什么用处,因为每次调用时都会将 $a 的值设为 0 并输出 "0"。将变量加一的 $a++ 没有作用,因为一旦退出本函数则变量 $a 就不存在了。要写一个不会丢失本次计数值的计数函数,要将变量 $a 定义为静态的:

例子 12-5. 使用静态变量的例子

<?php
function Test()
{
   static $a = 0;
   echo $a;
   $a++;
}
?> 

现在,每次调用 Test() 函数都会输出 $a 的值并加一。

静态变量也提供了一种处理递归函数的方法。递归函数是一种调用自己的函数。写递归函数时要小心,因为可能会无穷递归下去。必须确保有充分的方法来中止递归。一下这个简单的函数递归计数到 10,使用静态变量 $count 来判断何时停止:

例子 12-6. 静态变量与递归函数

<?php
function Test()
{
   static $count = 0;
   $count++;
   echo $count;
   if ($count < 10) {
   Test ();
   }
   $count--;
}
?> 

注: 静态变量可以按照上面的例子声明。如果在声明中用表达式的结果对其赋值会导致解析错误。

例子 12-7. 声明静态变量

<?php
function foo(){
   static $int = 0; // correct
   static $int = 1+2; // wrong (as it is an expression)
   static $int = sqrt(121); // wrong (as it is an expression too)
   $int++;
   echo $int;
}
?> 

全局和静态变量的引用
在 Zend 引擎 1 代,驱动了 PHP4,对于变量的 static 和 global 定义是以 references 的方式实现的。例如,在一个函数域内部用 global 语句导入的一个真正的全局变量实际上是建立了一个到全局变量的引用。这有可能导致预料之外的行为,如以下例子所演示的:
<?php
function test_global_ref() {
   global $obj;
   $obj = &new stdclass;
}
function test_global_noref() {
   global $obj;
   $obj = new stdclass;
}
test_global_ref();
var_dump($obj);
test_global_noref();
var_dump($obj);
?> 

执行以上例子会导致如下输出:
NULLobject(stdClass)(0) {}
类似的行为也适用于 static 语句。引用并不是静态地存储的:
<?php
function &get_instance_ref() {
   static $obj;
   echo "Static object: ";
   var_dump($obj);
   if (!isset($obj)) {
   // 将一个引用赋值给静态变量
   $obj = &new stdclass;
   }
   $obj->property++;
   return $obj;
}
function &get_instance_noref() {
   static $obj;
   echo "Static object: ";
   var_dump($obj);
   if (!isset($obj)) {
   // 将一个对象赋值给静态变量
   $obj = new stdclass;
   }
   $obj->property++;
   return $obj;
}
$obj1 = get_instance_ref();
$still_obj1 = get_instance_ref();
echo "/n";
$obj2 = get_instance_noref();
$still_obj2 = get_instance_noref();
?> 

执行以上例子会导致如下输出:
Static object: NULLStatic object: NULLStatic object: NULLStatic object: object(stdClass)(1) {  ["property"]=>  int(1)} 上例演示了当把一个引用赋值给一个静态变量时,第二次调用 &get_instance_ref() 函数时其值并没有被记住。
PHP 相关文章推荐
一个高ai的分页函数和一个url函数
Oct 09 PHP
PHP个人网站架设连环讲(四)
Oct 09 PHP
PHP CKEditor 上传图片实现代码
Nov 06 PHP
php URL跳转代码 减少外链
Jun 25 PHP
php自动注册登录验证机制实现代码
Dec 20 PHP
phpMyAdmin出现无法载入 mcrypt 扩展,请检查PHP配置的解决方法
Mar 26 PHP
PHP中isset()和unset()函数的用法小结
Mar 11 PHP
学习php设计模式 php实现合成模式(composite)
Dec 08 PHP
PHP实现Google plus的好友拖拽分组效果
Oct 21 PHP
php正则判断是否为合法身份证号的方法
Mar 16 PHP
php微信公众号开发之图片回复
Oct 20 PHP
YII框架关联查询操作示例
Apr 29 PHP
解析php开发中的中文编码问题
Aug 08 #PHP
php中jpgraph类库的使用介绍
Aug 08 #PHP
浅析php与数据库代码开发规范
Aug 08 #PHP
九个你必须知道而且又很好用的php函数和特点
Aug 08 #PHP
怎样使用php与jquery设置和读取cookies
Aug 08 #PHP
如何取得中文字符串中出现次数最多的子串
Aug 08 #PHP
php读取图片内容并输出到浏览器的实现代码
Aug 08 #PHP
You might like
PHP获取网站域名和地址的代码
2008/08/17 PHP
一个php Mysql类 可以参考学习熟悉下
2009/06/21 PHP
php防注入,表单提交值转义的实现详解
2013/06/10 PHP
php操作xml
2013/10/27 PHP
纯php生成随机密码
2015/10/30 PHP
PHP测试框架PHPUnit组织测试操作示例
2018/05/28 PHP
JQuery datepicker 使用方法
2011/05/20 Javascript
基于jQuery中对数组进行操作的方法
2013/04/16 Javascript
jquery选择器之基本过滤选择器详解
2014/01/27 Javascript
jquery操作对象数组元素方法详解
2014/11/26 Javascript
asp.net+js实现金额格式化
2015/02/27 Javascript
js文字横向滚动特效
2015/11/11 Javascript
使用jQuery的easydrag插件实现可拖动的DIV弹出框
2016/02/19 Javascript
javascript检查某个元素在数组中的索引值
2016/03/30 Javascript
canvas实现图像截取功能
2017/02/06 Javascript
利用ES6语法重构React组件详解
2017/03/02 Javascript
vue中SPA单页面应用程序详解
2017/11/07 Javascript
通过seajs实现JavaScript的模块开发及按模块加载
2019/06/06 Javascript
微信小程序tabBar设置实例解析
2019/11/14 Javascript
Element DateTimePicker日期时间选择器的使用示例
2020/07/27 Javascript
解决在Vue中使用axios POST请求变成OPTIONS的问题
2020/08/14 Javascript
python分割和拼接字符串
2013/11/01 Python
python使用PyV8执行javascript代码示例分享
2013/12/04 Python
python中的装饰器详解
2015/04/13 Python
老生常谈python函数参数的区别(必看篇)
2017/05/29 Python
Python算法输出1-9数组形成的结果为100的所有运算式
2017/11/03 Python
python django下载大的csv文件实现方法分析
2019/07/19 Python
Python实现列表中非负数保留,负数转化为指定的数值方式
2020/06/04 Python
菲律宾领先的在线时尚商店:Zalora菲律宾
2018/02/08 全球购物
介绍一下linux文件系统分配策略
2012/11/17 面试题
战友聚会策划方案
2014/06/13 职场文书
超市理货员岗位职责
2014/07/04 职场文书
六年级作文之家庭作文
2019/12/12 职场文书
JavaScript嵌入百度地图API的最详细方法
2021/04/16 Javascript
python多线程方法详解
2022/01/18 Python
教你使用RustDesk 搭建一个自己的远程桌面中继服务器
2022/08/14 Servers