php变量作用域的深入解析

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() 函数时其值并没有被记住。

(0)

相关推荐

  • 浅析php变量修饰符static的使用

    静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失.看看下面的例子: 复制代码 代码如下: function test(){static $a=0;$a++;echo $a;} test();//1test();//2test();//3Note: 静态变量可以按照上面的例子声明.如果在声明中用表达式的结果对其赋值会导致解析错误. 复制代码 代码如下: static $a=0+1;static $a=sqrt(121); 像上面的赋值方式会报错,不信你试试

  • PHP变量内存分配问题记录整理

    今天碰到一个关于php变量内存分配的问题,记录一下. 如下这段代码: 复制代码 代码如下: $a = array ( 'str' => 1, 'child' => 2 ); $b = $a; $b['child'] = $a; $b['child']['str'] = 2; echo $b['str']; $b = null; echo $a['str']; 会输出什么呢,结果是11,$b=$a的时候其实并没有新分配内存,ab是指向的同一个区域,$b['child']=$a时,$b会先copy

  • PHP变量的定义、可变变量、变量引用、销毁方法

    复制代码 代码如下: <?php$long="big_long_variable_name";$$long="PHP";     /* 用存放在变量$long里的字符串作为新变量的变量名,等同于$big_long_variable_name="PHP"; */$short=& $big_long_variable_name;  /* 取变量$big_long_variable_name的值赋给变量$short,此时$short的值为

  • 浅谈PHP变量作用域以及地址引用问题

    作用域的概念: 在PHP脚本的任何位置都可以声明变量,但是,声明变量的位置会大大影响访问变量的范围.这个可以访问的范围称为作用域. 主要的常用的包括:局部变量.全局变量.静态变量. 1.局部变量:就是在函数内声明的变量,他保存在内存的栈内,所以访问速度很快.仅在函数内有效. 2.全局变量:与局部变量相反,全局变量可以在程序的任何地方访问.只要在变量前面加关键字GLOBAL,就可以将其识别为全局变量.在整个php文件内有效. 3.静态变量:用static修饰只存在于函数作用域的变量,函数执行结束后

  • php变量范围介绍

    例如: 复制代码 代码如下: <?php $a = 1; include 'b.inc'; ?> 这里变量 $a 将会在包含文件 b.inc 中生效.但是,在用户自定义函数中,一个局部函数范围将被引入.任何用于函数内部的变量按缺省情况将被限制在局部函数范围内,此时为局部变量. PHP 中全局变量在函数中使用时必须申明为global. 在函数中使用global声明的变量即为全局变量,可以在函数外使用.注意:global声明变量时,不能直接对变量赋值,需要先声明后赋值. 在全局范围内,也可以通过$

  • 深入PHP变量存储的详解

    1.1.1 zval结构Zend使用zval结构来存储PHP变量的值,该结构如下所示: 复制代码 代码如下: typedef union _zvalue_value { long lval;    /* long value */ double dval;    /* double value */ struct {  char *val;  int len; } str; HashTable *ht;    /* hash table value */ zend_object_value ob

  • 神盾加密解密教程(一)PHP变量可用字符

    先来说说php变量的命名规则,百度下一抓一大把:(1) PHP的变量名区分大小写;(2) 变量名必须以美元符号$开始;(3) 变量名开头可以以下划线开始;(4) 变量名不能以数字字符开头. 其实所有编程都类似的命名规范就是:1. 变量第一个字符最好是 字母或_,不能以数字开头2. 第二个字符开始允许 数字,字母,_ 好了,差不多就是这样了,但是这不是我们要说的重点.今天我们说说 PHP 变量的可用字符,不仅仅是 数字,字母,_ 哦. 前几天QQ上一朋友发我一个shell,是加密过的,通篇乱码,不

  • Python变量作用域LEGB用法解析

    这篇文章主要介绍了Python变量作用域LEGB用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 闭包就是, 函数内部嵌套函数. 而 装饰器只是闭包的特殊场景而已, 特殊在如果外函数的参数是指向一个, 用来被装饰的函数地址时(不一定是地址哈, 随意就好) , 就有了 "@xxx" 这样的写法, 还是蛮有意思的. 装饰器的作用是 在不改变原函数的代码前提下, 额外给原函数填写新功能. 写法上来看, 还是比较简洁优雅的. 装饰器的通

  • php变量作用域的深入解析

    PHP 中的每个变量都有一个针对它的作用域,它是指可以在其中访问变量(从而访问它的值)的一个领域.对于初学者来说,变量的作用域是它们所驻留的页面.因此,如果你定义了 $var,页面余下部分就可以访问 $var,但是,其它页面一般不能访问它(除非使用特殊的变量). 因为包含文件像它们是原始(包含)脚本的一部分那样工作,所以在 include() 那一行之前定义的变量可供包含文件使用.此外,包含文件内定义的变量可供 include() 那一行之后的父(包含)脚本使用. 当使用你自己定义的函数时,所有

  • 详解js的作用域、预解析机制

    虽然,ES6在我们工作中应用得越来越广泛,但是还是很多项目保留着ES5的写法,所以,今天,带着大家重新巩固下ES5下的作用域及预解析机制. 概念: 作用域:域,指的是一个空间.范围.区域,作用指的是在域内可进行读写操作.一个变量的作用域是程序源代码中定义的这个变量的区域. 在ES5中,只存在全局和函数级作用域,在ES6中,引入了块级作用域,js的预解析机制大概分为两个过程:预解析和自上而下逐行解读 预解析:js解析器会先把var定义的变量.function.参数等一些东西存储进仓库里面(内存).

  • 深度解析C语言中的变量作用域、链接和存储期的含义

    在c中变量有三种性质: 1.存储期限:变量的存储期限决定了变量占用的内存空间什么时候会被释放,具有动态存储期限的变量会在所属的程序块被执行时获得内存空间,在结束时释放内存空间.具有静态存储期限的变量在程序运行的整个期间都会占用内存空间. 2.作用域:变量有块作用域也有文件作用域,结合序章第一张图可以明白块作用域是在某些程序块内起作用,文件作用域是在整个c文件之内起作用. 3.链接:链接是各个文件之间的关系,具有内部链接的变量只在本文件内起作用,具有外部链接的变量可以在不同文件内起作用.具有无链接

  • Python编程中闭包的变量作用域问题解析

    目录 闭包 闭包中的变量 闭包 ​ 在我们使用返回函数的时候,由于我们在一个函数中需要返回另一个函数,因此,我们在这个函数中就需要重新定义一个函数.而这样,就造成了我们的函数嵌套问题.外面的函数相对于里面的函数而言是外函数(outer function),而里面的我们叫他内函数(inner function). def outerFunction(): #外函数 def innerFunction(): #内函数 x = 1 return x return innerFunction #返回值是

  • 深入解析JavaScript中的变量作用域

    在学习JavaScript的变量作用域之前,我们应当明确几点: •JavaScript的变量作用域是基于其特有的作用域链的. •JavaScript没有块级作用域. •函数中声明的变量在整个函数中都有定义. 1.JavaScript的作用域链首先看下下面这段代码: 复制代码 代码如下: <script type="text/javascript"> var rain = 1; function rainman(){ var man = 2; function inner()

  • 理解JavaScript变量作用域更轻松

    JavaScript本身作为一门简单的语言,就其变量作用域问题一样令不少人头晕,这主要是因为JavaScript闭包的存在.本文不打算深入讲解JavaScript变量作用域问题(其实本人也没有能力能把这一话题讲的深入些),也不讲"闭包"话题,本文只讨论最实用的JavaScript作用域知识点. 一.JavaScript作用域分类 JavaScript就两种作用域:全局(window).函数级(function).函数级(function)不要理解为"块级(大括号{}级)&qu

  • javascript变量作用域使用中常见错误总结

    今天在rainweb的博客上,看到了这篇非常好的文章,觉得非常有必要分享出来,相信大家认真读完这篇文章,对js作用域的理解又会上升到一个新的台阶. 前言:javascript里变量作用域是个经常让人头痛抓狂的问题,下面通过10++个题目,对经常遇到又容易出错的情况进行了简单总结,代码样例很短很简单 题目一 复制代码 代码如下: var name = 'casper'; alert(name); //毫无疑问地输出:casper 题目二 复制代码 代码如下: alert(name); //报错:对

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

    昨晚就与到这么一个问题,是全局变量在函数中的问题.今天搜索了一下,发现一篇相当不错的文章,讲了php中的变量作用域.是一位网友翻译的在这贴一下: 变量范围变量的范围即它定义的上下文背景(译者:说白了,也就是它的生效范围).大部分的 PHP 变量只有一个单独的范围.这个单独的范围跨度同样包含了 include 和 require 引入的文件.范例: 复制代码 代码如下: <?php$a = 1;include "b.inc";?> 这里变量 $a 将会在包含文件 b.inc

  • JavaScript变量作用域及内存问题实例分析

    本文实例讲述了JavaScript变量作用域及内存问题.分享给大家供大家参考,具体如下: 学习要点: 1.变量及作用域 2.内存问题 JavaScript的变量与其他语言的变量有很大区别.JavaScript变量是松散型的(不强制类型)本质,决定了它只是在特定时间用于保存特定值的一个名字而已.由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变. 一.变量及作用域 1.基本类型和引用类型的值 ECMAScript变量可能包含两种不同的数据类型的值:

随机推荐