浅析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 相关文章推荐
Zend Studio (eclipse)使用速度优化方法
Mar 23 PHP
探讨如何在php168_cms中提取验证码
Jun 08 PHP
php+ajax导入大数据时产生的问题处理
Jun 11 PHP
详谈PHP文件目录基础操作
Nov 11 PHP
分享十款最出色的PHP安全开发库中文详细介绍
Mar 22 PHP
Zend Framework自定义Helper类相关注意事项总结
Mar 14 PHP
PHP字典树(Trie树)定义与实现方法示例
Oct 09 PHP
可兼容php5与php7的cURL文件上传功能实例分析
May 11 PHP
PHP封装的mysqli数据库操作类示例
Feb 16 PHP
thinkphp5框架调用其它控制器方法 实现自定义跳转界面功能示例
Jul 03 PHP
Laravel 错误提示本地化的实现
Oct 22 PHP
php 中self,this的区别和操作方法实例分析
Nov 04 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
drupal 代码实现URL重写
2011/05/04 PHP
php读取目录及子目录下所有文件名的方法
2014/10/20 PHP
WordPress主题中添加文章列表页页码导航的PHP代码实例
2015/12/22 PHP
PHP正则表达式入门教程(推荐)
2016/05/18 PHP
ThinkPHP表单令牌错误的相关解决方法分析
2016/05/20 PHP
利用PHP内置SERVER开启web服务(本地开发使用)
2020/01/22 PHP
PHP pthreads v3在centos7平台下的安装与配置操作方法
2020/02/21 PHP
再谈Yii Framework框架中的事件event原理与应用
2020/04/07 PHP
PHP设计模式之 策略模式Strategy详解【对象行为型】
2020/05/01 PHP
javascript实现tabs选项卡切换效果(自写原生js)
2013/03/19 Javascript
js操作iframe的一些方法介绍
2013/06/25 Javascript
js网页版计算器的简单实现
2013/07/02 Javascript
jquery+json实现数据列表分页示例代码
2013/11/15 Javascript
node.js WEB开发中图片验证码的实现方法
2014/06/03 Javascript
解决Jquery向页面append新元素之后事件的绑定问题
2015/03/16 Javascript
详解JavaScript编程中的数组结构
2015/10/24 Javascript
谈谈我对JavaScript原型和闭包系列理解(随手笔记9)
2015/12/24 Javascript
javascript数组去重小结
2016/03/07 Javascript
谈谈对JavaScript原生拖放的深入理解
2016/09/20 Javascript
jQuery双向列表选择器select版
2016/11/01 Javascript
基于Python实现的扫雷游戏实例代码
2014/08/01 Python
python数据类型_元组、字典常用操作方法(介绍)
2017/05/30 Python
Python格式化输出%s和%d
2018/05/07 Python
python 自动批量打开网页的示例
2019/02/21 Python
解决python中用matplotlib画多幅图时出现图形部分重叠的问题
2019/07/07 Python
python实现最小二乘法线性拟合
2019/07/19 Python
face++与python实现人脸识别签到(考勤)功能
2019/08/28 Python
Python 炫技操作之合并字典的七种方法
2020/04/10 Python
html5实现输入框fixed定位在屏幕最底部兼容性
2020/07/03 HTML / CSS
bonprix匈牙利:女士、男士和儿童服装
2019/07/19 全球购物
应届生求职自荐信
2014/07/04 职场文书
营业员岗位职责
2015/02/11 职场文书
2015年小学生国庆节演讲稿
2015/07/30 职场文书
2016年社区党支部公开承诺书
2016/03/25 职场文书
使用Python脚本对GiteePages进行一键部署的使用说明
2021/05/27 Python
python 使用tkinter与messagebox写界面和弹窗
2022/03/20 Python