php变量作用域的深入解析


Posted in PHP onJune 03, 2013

PHP 中的每个变量都有一个针对它的作用域,它是指可以在其中访问变量(从而访问它的值)的一个领域。对于初学者来说,变量的作用域是它们所驻留的页面。因此,如果你定义了 $var,页面余下部分就可以访问 $var,但是,其它页面一般不能访问它(除非使用特殊的变量)。

因为包含文件像它们是原始(包含)脚本的一部分那样工作,所以在 include() 那一行之前定义的变量可供包含文件使用。此外,包含文件内定义的变量可供 include() 那一行之后的父(包含)脚本使用。

当使用你自己定义的函数时,所有这些都将变得不那么明显。这些函数具有它们自己的作用域,这意味着在一个函数内使用的变量不能在其外部使用,在一个函数外部定义的变量不能在其内部使用。由于这个原因,函数内部的变量可以具有与其外部的变量相同的名称,但是它们仍然是完全不同的变量,并且具有不同的值。对于大多数初级程序员来说,这是一个使人糊涂的概念。
要改变一个函数内的变量的作用域,可以使用 global 语句。

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?php
function function_name() {
    global $var;
}
$var=20;
function_name(); // Function call.
?>

在这个示例中,函数内部的 $var 现在与函数外部的 $var 相同。这意味着变量 $var 已经具有一个值20,如果在函数内部改变了这个值,外部的 $var 值也会改变。
避开变量作用域的另一个方法是利用超全局变量:$_GET、$_POST、$_REQUEST 等。这些变量在你的函数内是自动可访问的(因此,它们是超全局变量)。也可以添加元素到 $GLOBALS 数组中,使得可以在函数内使用它们。

也就是说,最好不要在函数内使用全局变量。在设计函数时,应该使它们根据需要接受每个值作为参数,并根据需要返回任何值。依靠函数内的全局变量将使得它们更依赖于上下文,因而不太有用。
在PHP中变量主要有:内置超级全局变量,一般的变量,常量,全局变量,静态变量等.

内置超级全局变量可以在脚本的任何地方使用和可见。即如果我们在一个PHP页面中改变了其中的一个值,那么在其他PHP页面中使用时,它的值也会发生改变。

•常量一旦被声明将可以在全局可见,也就是说,它们可以函数内外使用,但是这仅仅限于一个页面之中(包含我们通过include和include_once)包含进来的PHP脚本,但是在其他的页面中就不能使用了。
•在一个脚本中声明的全局变量在整个脚本中是可见的,但不是在函数内部,在函数内部的变量如果与全局变量名称相同,以函数内部的变量为准。
•函数内部使用的变量声明为全局变量时,其名称要与全局变量的名称一致,在这样的情况下,我们就可以在函数中使用函数外部的全局变量了,这样就可以避免上一种因为函数内部的变量与外部的全局变量名称相同而覆盖了外部变量这样的情况。
•在函数内部创建并声明为静态的变量无法在函数外部可见,但是可以在函数的多次执行过程中保持该值,最常见的情况就是在函数的递归执行的过程之中。
•在函数内部创建的变量对函数来说是本地的,而当函数终止时,该变量也就不存在了。
超级全局变量的完整列表如下:
•.$GOBALS 所有全局变量数组
•.$_SERVER 服务器环境变量数组
•.$_POST 通过POST方法传递给该脚本的变量数组
•.$_GET 通过GET方法传递给该脚本的变量数组
•.$_COOKIE cookie变量数组
•.$_FILES 与文件上传相关的变量数组
•.$_ENV 环境变量数组
•.$_REQUEST 所有用户输入的变量数组包括$_GET $_POST $_COOKIE 所包含的输入内容
•.$_SESSION 会话变量数组
实例讲解:

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?php 
   $a = 4;
   function sendValue($x)
     {
        echo $x;
     }
    sendValue($a);
?>

讲解: $a定义在函数外,函数定义了参数,当函数被调用时,$a将以参数的形式被传递。因此上面代码能够正常运行。
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?php 
    $a = 4;
    function sendValue()
     {
       echo $a;
    }
    sendValue();
?>

讲解:当函数被调用时,$a不能以参数的形式被传递。所以上面代码不能够正常运行。
变量范围
变量的范围即它定义的上下文背景(译者:说白了,也就是它的生效范围)。大部分的 PHP 变量只有一个单独的范围。这个单独的范围跨度同样包含了 include 和 require 引入的文件。范例:
<?php
  $a = 1;
  include "b.inc";
?>

这里变量 $a 将会在包含文件 b.inc 中生效。但是,在用户自定义函数中,一个局部函数范围将被引入。任何用于函数内部的变量按缺省情况将被限制在局部函数范围内。范例:
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?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
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?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
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?php
$a = 1;
$b = 2;
function Sum()
{
   $GLOBALS["b"] = $GLOBALS["a"] + $GLOBALS["b"];
}
Sum();
echo $b;
?>

在 $GLOBALS 数组中,每一个变量为一个元素,键名对应变量名,值变量的内容。$GLOBALS 之所以在全局范围内存在,是因为 $GLOBALS 是一个超全局变量。以下范例显示了超全局变量的用处:
例子 12-3. 演示超全局变量和作用域的例子
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?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. 演示需要静态变量的例子
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?php
function Test ()
{
   $a = 0;
   echo $a;
   $a++;
}
?>

本函数没什么用处,因为每次调用时都会将 $a 的值设为 0 并输出 "0"。将变量加一的 $a++ 没有作用,因为一旦退出本函数则变量 $a 就不存在了。要写一个不会丢失本次计数值的计数函数,要将变量 $a 定义为静态的:
例子 12-5. 使用静态变量的例子
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?php
function Test()
{
   static $a = 0;
   echo $a;
   $a++;
}
?>

现在,每次调用 Test() 函数都会输出 $a 的值并加一。
静态变量也提供了一种处理递归函数的方法。递归函数是一种调用自己的函数。写递归函数时要小心,因为可能会无穷递归下去。必须确保有充分的方法来中止递归。一下这个简单的函数递归计数到 10,使用静态变量 $count 来判断何时停止:
例子 12-6. 静态变量与递归函数
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?php
function Test()
{
   static $count = 0;
   $count++;
   echo $count;
   if ($count < 10) {
   Test ();
   }
   $count--;
}
?>

注: 静态变量可以按照上面的例子声明。如果在声明中用表达式的结果对其赋值会导致解析错误。
例子 12-7. 声明静态变量
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?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 语句导入的一个真正的全局变量实际上是建立了一个到全局变量的引用。这有可能导致预料之外的行为,如以下例子所演示的:
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?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 语句。引用并不是静态地存储的:
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--><?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 相关文章推荐
十天学会php之第十天
Oct 09 PHP
PHP 中的一些经验积累
Oct 09 PHP
PHP 判断变量类型实现代码
Oct 23 PHP
PHP的substr_replace将指定两位置之间的字符替换为*号
May 04 PHP
php字符串函数学习之strstr()
Mar 27 PHP
PHP中is_file()函数使用指南
May 08 PHP
33道php常见面试题及答案
Jul 06 PHP
基于PHP技术开发客服工单系统
Jan 06 PHP
解决微信授权回调页面域名只能设置一个的问题
Dec 11 PHP
php使用PDO下exec()函数查询执行后受影响行数的方法
Mar 28 PHP
PHP设计模式之建造者模式定义与用法简单示例
Aug 13 PHP
PHP实现字符串的全排列详解
Apr 24 PHP
CURL的学习和应用(附多线程实现)
Jun 03 #PHP
php魔术方法与魔术变量、内置方法与内置变量的深入分析
Jun 03 #PHP
PHP flush()与ob_flush()的区别详解
Jun 03 #PHP
PHP导出EXCEL快速开发指南--PHPEXCEL的使用详解
Jun 03 #PHP
PHP Cookie的使用教程详解
Jun 03 #PHP
PHP register_shutdown_function函数的深入解析
Jun 03 #PHP
深入PHP与浏览器缓存的分析
Jun 03 #PHP
You might like
如何在PHP中使用Oracle数据库(4)
2006/10/09 PHP
php 动态执行带有参数的类方法
2009/04/10 PHP
windows下配置apache+php+mysql时出现问题的处理方法
2014/06/20 PHP
如何在PHP环境中使用ProtoBuf数据格式
2020/06/19 PHP
JS.findElementById()使用介绍
2013/09/21 Javascript
JavaScript Math.ceil() 函数使用介绍
2013/12/11 Javascript
11种ASP连接数据库的方法
2015/09/18 Javascript
深入剖析JavaScript面向对象编程
2016/07/12 Javascript
js实现点击图片自动提交action的简单方法
2016/10/16 Javascript
微信小程序中显示html格式内容的方法
2017/04/25 Javascript
React Native验证码倒计时工具类分享
2017/10/24 Javascript
使用Bootstrap和Vue实现用户信息的编辑删除功能
2017/10/25 Javascript
Angularjs渲染的 using 指令的星级评分系统示例
2017/11/09 Javascript
JS实现多物体运动的方法详解
2018/01/23 Javascript
Vue 项目代理设置的优化
2018/04/17 Javascript
使用xampp将angular项目运行在web服务器的教程
2019/09/16 Javascript
[02:19]2014DOTA2国际邀请赛 专访820少年们一起去追梦吧
2014/07/14 DOTA
Python使用PyGreSQL操作PostgreSQL数据库教程
2014/07/30 Python
python中使用PIL制作并验证图片验证码
2018/03/15 Python
详解Python Matplot中文显示完美解决方案
2019/03/07 Python
python GUI模拟实现计算器
2020/06/22 Python
Nisbets爱尔兰:英国最大的厨房和餐饮设备供应商
2019/01/26 全球购物
在家更换处方镜片:Lensabl
2019/05/01 全球购物
Ray-Ban雷朋瑞典官方网站:全球领先的太阳眼镜品牌
2019/08/22 全球购物
StudentUniverse英国:学生航班、酒店和旅游
2019/08/25 全球购物
中青班党性分析材料
2014/02/16 职场文书
办公室文员岗位职责范本
2014/06/12 职场文书
幼儿教师辞职信范文
2015/03/02 职场文书
欠款起诉书范文
2015/05/19 职场文书
儿子满月酒致辞
2015/07/29 职场文书
期中考试后的感想
2015/08/07 职场文书
生活委员竞选稿
2015/11/21 职场文书
如何写好一份优秀的工作总结?
2019/06/21 职场文书
利用前端HTML+CSS+JS开发简单的TODOLIST功能(记事本)
2021/04/13 Javascript
python 解决微分方程的操作(数值解法)
2021/05/26 Python
MyBatis自定义SQL拦截器示例详解
2021/10/24 Java/Android