<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML ><HEAD ><TITLE >变量范围</TITLE ><META NAME="GENERATOR" CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK REL="HOME" TITLE="PHP 手册" HREF="index.html"><LINK REL="UP" TITLE="变量" HREF="language.variables.html"><LINK REL="PREVIOUS" TITLE="预定义变量" HREF="language.variables.predefined.html"><LINK REL="NEXT" TITLE="可变变量" HREF="language.variables.variable.html"><META HTTP-EQUIV="Content-type" CONTENT="text/html; charset=UTF-8"></HEAD ><BODY CLASS="sect1" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#840084" ALINK="#0000FF" ><DIV CLASS="NAVHEADER" ><TABLE SUMMARY="Header navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TH COLSPAN="3" ALIGN="center" >PHP 手册</TH ></TR ><TR ><TD WIDTH="10%" ALIGN="left" VALIGN="bottom" ><A HREF="language.variables.predefined.html" ACCESSKEY="P" >上一页</A ></TD ><TD WIDTH="80%" ALIGN="center" VALIGN="bottom" >章 12. 变量</TD ><TD WIDTH="10%" ALIGN="right" VALIGN="bottom" ><A HREF="language.variables.variable.html" ACCESSKEY="N" >下一页</A ></TD ></TR ></TABLE ><HR ALIGN="LEFT" WIDTH="100%"></DIV ><DIV CLASS="sect1" ><H1 CLASS="sect1" ><A NAME="language.variables.scope" >变量范围</A ></H1 ><P > 变量的范围即它定义的上下文背景(也就是它的生效范围)。大部分的 PHP 变量只有一个单独的范围。这个单独的范围跨度同样包含了 include 和 require 引入的文件。例如: </P ><DIV CLASS="informalexample" ><P ></P ><A NAME="AEN3694" ></A ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br />$a </font><font color="#007700">= </font><font color="#0000BB">1</font><font color="#007700">;<br />include </font><font color="#DD0000">'b.inc'</font><font color="#007700">;<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ><P ></P ></DIV ><P > 这里变量 <CODE CLASS="varname" >$a</CODE > 将会在包含文件 <TT CLASS="filename" >b.inc</TT > 中生效。但是,在用户自定义函数中,一个局部函数范围将被引入。任何用于函数内部的变量按缺省情况将被限制在局部函数范围内。例如: </P ><DIV CLASS="informalexample" ><P ></P ><A NAME="AEN3699" ></A ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br />$a </font><font color="#007700">= </font><font color="#0000BB">1</font><font color="#007700">; </font><font color="#FF8000">/* global scope */<br /><br /></font><font color="#007700">function </font><font color="#0000BB">Test</font><font color="#007700">()<br />{<br /> echo </font><font color="#0000BB">$a</font><font color="#007700">; </font><font color="#FF8000">/* reference to local scope variable */<br /></font><font color="#007700">}<br /><br /></font><font color="#0000BB">Test</font><font color="#007700">();<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ><P ></P ></DIV ><P > 这个脚本不会有任何输出,因为 echo 语句引用了一个局部版本的变量 <CODE CLASS="varname" >$a</CODE >,而且在这个范围内,它并没有被赋值。你可能注意到 PHP 的全局变量和 C 语言有一点点不同,在 C 语言中,全局变量在函数中自动生效,除非被局部变量覆盖。这可能引起一些问题,有些人可能漫不经心的改变一个全局变量。PHP 中全局变量在函数中使用时必须申明为全局。 </P ><DIV CLASS="sect2" ><H2 CLASS="sect2" ><A NAME="language.variables.scope.global" >global 关键字</A ></H2 ><P > 首先,一个使用 <TT CLASS="literal" >global</TT > 的例子: </P ><P > <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN3708" ></A ><P ><B >例 12-2. 使用 global</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br />$a </font><font color="#007700">= </font><font color="#0000BB">1</font><font color="#007700">;<br /></font><font color="#0000BB">$b </font><font color="#007700">= </font><font color="#0000BB">2</font><font color="#007700">;<br /><br />function </font><font color="#0000BB">Sum</font><font color="#007700">()<br />{<br /> global </font><font color="#0000BB">$a</font><font color="#007700">, </font><font color="#0000BB">$b</font><font color="#007700">;<br /><br /> </font><font color="#0000BB">$b </font><font color="#007700">= </font><font color="#0000BB">$a </font><font color="#007700">+ </font><font color="#0000BB">$b</font><font color="#007700">;<br />}<br /><br /></font><font color="#0000BB">Sum</font><font color="#007700">();<br />echo </font><font color="#0000BB">$b</font><font color="#007700">;<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </P ><P > 以上脚本的输出将是“3”。在函数中申明了全局变量 <CODE CLASS="varname" >$a</CODE > 和 <CODE CLASS="varname" >$b</CODE >,任何变量的所有引用变量都会指向到全局变量。对于一个函数能够申明的全局变量的最大个数,PHP 没有限制。 </P ><P > 在全局范围内访问变量的第二个办法,是用特殊的 PHP 自定义 <CODE CLASS="varname" >$GLOBALS</CODE > 数组。前面的例子可以写成: </P ><P > <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN3717" ></A ><P ><B >例 12-3. 使用 <CODE CLASS="varname" >$GLOBALS</CODE > 替代 global</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br />$a </font><font color="#007700">= </font><font color="#0000BB">1</font><font color="#007700">;<br /></font><font color="#0000BB">$b </font><font color="#007700">= </font><font color="#0000BB">2</font><font color="#007700">;<br /><br />function </font><font color="#0000BB">Sum</font><font color="#007700">()<br />{<br /> </font><font color="#0000BB">$GLOBALS</font><font color="#007700">[</font><font color="#DD0000">'b'</font><font color="#007700">] = </font><font color="#0000BB">$GLOBALS</font><font color="#007700">[</font><font color="#DD0000">'a'</font><font color="#007700">] + </font><font color="#0000BB">$GLOBALS</font><font color="#007700">[</font><font color="#DD0000">'b'</font><font color="#007700">];<br />}<br /><br /></font><font color="#0000BB">Sum</font><font color="#007700">();<br />echo </font><font color="#0000BB">$b</font><font color="#007700">;<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </P ><P > 在 <CODE CLASS="varname" >$GLOBALS</CODE > 数组中,每一个变量为一个元素,键名对应变量名,值对应变量的内容。<CODE CLASS="varname" >$GLOBALS</CODE > 之所以在全局范围内存在,是因为 $GLOBALS 是一个<A HREF="language.variables.predefined.html#language.variables.superglobals" >超全局变量</A >。以下范例显示了超全局变量的用处: </P ><P > <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN3726" ></A ><P ><B >例 12-4. 演示超全局变量和作用域的例子</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br /></font><font color="#007700">function </font><font color="#0000BB">test_global</font><font color="#007700">()<br />{<br /> </font><font color="#FF8000">// 大多数的预定义变量并不 "super",它们需要用 'global' 关键字来使它们在函数的本地区域中有效。<br /> </font><font color="#007700">global </font><font color="#0000BB">$HTTP_POST_VARS</font><font color="#007700">;<br /><br /> echo </font><font color="#0000BB">$HTTP_POST_VARS</font><font color="#007700">[</font><font color="#DD0000">'name'</font><font color="#007700">];<br /><br /> </font><font color="#FF8000">// Superglobals 在任何范围内都有效,它们并不需要 'global' 声明。Superglobals 是在 PHP 4.1.0 引入的。<br /> </font><font color="#007700">echo </font><font color="#0000BB">$_POST</font><font color="#007700">[</font><font color="#DD0000">'name'</font><font color="#007700">];<br />}<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </P ></DIV ><DIV CLASS="sect2" ><H2 CLASS="sect2" ><A NAME="language.variables.scope.static" >使用静态变量</A ></H2 ><P > 变量范围的另一个重要特性是<SPAN CLASS="emphasis" ><I CLASS="emphasis" >静态变量</I ></SPAN >(static variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子: </P ><P > <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN3734" ></A ><P ><B >例 12-5. 演示需要静态变量的例子</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br /></font><font color="#007700">function </font><font color="#0000BB">Test</font><font color="#007700">()<br />{<br /> </font><font color="#0000BB">$a </font><font color="#007700">= </font><font color="#0000BB">0</font><font color="#007700">;<br /> echo </font><font color="#0000BB">$a</font><font color="#007700">;<br /> </font><font color="#0000BB">$a</font><font color="#007700">++;<br />}<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </P ><P > 本函数没什么用处,因为每次调用时都会将 <CODE CLASS="varname" >$a</CODE > 的值设为 <TT CLASS="literal" >0</TT > 并输出 "0"。将变量加一的 <CODE CLASS="varname" >$a</CODE >++ 没有作用,因为一旦退出本函数则变量 <CODE CLASS="varname" >$a</CODE > 就不存在了。要写一个不会丢失本次计数值的计数函数,要将变量 <CODE CLASS="varname" >$a</CODE > 定义为静态的: </P ><P > <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN3744" ></A ><P ><B >例 12-6. 使用静态变量的例子</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br /></font><font color="#007700">function </font><font color="#0000BB">Test</font><font color="#007700">()<br />{<br /> static </font><font color="#0000BB">$a </font><font color="#007700">= </font><font color="#0000BB">0</font><font color="#007700">;<br /> echo </font><font color="#0000BB">$a</font><font color="#007700">;<br /> </font><font color="#0000BB">$a</font><font color="#007700">++;<br />}<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </P ><P > 现在,每次调用 Test() 函数都会输出 <CODE CLASS="varname" >$a</CODE > 的值并加一。 </P ><P > 静态变量也提供了一种处理递归函数的方法。递归函数是一种调用自己的函数。写递归函数时要小心,因为可能会无穷递归下去。必须确保有充分的方法来中止递归。一下这个简单的函数递归计数到 10,使用静态变量 <CODE CLASS="varname" >$count</CODE > 来判断何时停止: </P ><P > <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN3752" ></A ><P ><B >例 12-7. 静态变量与递归函数</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br /></font><font color="#007700">function </font><font color="#0000BB">Test</font><font color="#007700">()<br />{<br /> static </font><font color="#0000BB">$count </font><font color="#007700">= </font><font color="#0000BB">0</font><font color="#007700">;<br /><br /> </font><font color="#0000BB">$count</font><font color="#007700">++;<br /> echo </font><font color="#0000BB">$count</font><font color="#007700">;<br /> if (</font><font color="#0000BB">$count </font><font color="#007700">< </font><font color="#0000BB">10</font><font color="#007700">) {<br /> </font><font color="#0000BB">Test</font><font color="#007700">();<br /> }<br /> </font><font color="#0000BB">$count</font><font color="#007700">--;<br />}<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </P ><DIV CLASS="note" ><BLOCKQUOTE CLASS="note" ><P ><B >注意: </B > 静态变量可以按照上面的例子声明。如果在声明中用表达式的结果对其赋值会导致解析错误。 </P ><P > <TABLE WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" CLASS="EXAMPLE" ><TR ><TD ><DIV CLASS="example" ><A NAME="AEN3758" ></A ><P ><B >例 12-8. 声明静态变量</B ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br /></font><font color="#007700">function </font><font color="#0000BB">foo</font><font color="#007700">(){<br /> static </font><font color="#0000BB">$int </font><font color="#007700">= </font><font color="#0000BB">0</font><font color="#007700">; </font><font color="#FF8000">// correct<br /> </font><font color="#007700">static </font><font color="#0000BB">$int </font><font color="#007700">= </font><font color="#0000BB">1</font><font color="#007700">+</font><font color="#0000BB">2</font><font color="#007700">; </font><font color="#FF8000">// wrong (as it is an expression)<br /> </font><font color="#007700">static </font><font color="#0000BB">$int </font><font color="#007700">= </font><font color="#0000BB">sqrt</font><font color="#007700">(</font><font color="#0000BB">121</font><font color="#007700">); </font><font color="#FF8000">// wrong (as it is an expression too)<br /><br /> </font><font color="#0000BB">$int</font><font color="#007700">++;<br /> echo </font><font color="#0000BB">$int</font><font color="#007700">;<br />}<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ></DIV ></TD ></TR ></TABLE > </P ></BLOCKQUOTE ></DIV ></DIV ><DIV CLASS="sect2" ><H2 CLASS="sect2" ><A NAME="language.variables.scope.references" >全局和静态变量的引用</A ></H2 ><P > 在 Zend 引擎 1 代,它驱动了 PHP4,对于变量的 <A HREF="language.variables.scope.html#language.variables.scope.static" >static</A > 和 <A HREF="language.variables.scope.html#language.variables.scope.global" >global</A > 定义是以 <A HREF="language.references.html" >references</A > 的方式实现的。例如,在一个函数域内部用 <TT CLASS="literal" >global</TT > 语句导入的一个真正的全局变量实际上是建立了一个到全局变量的引用。这有可能导致预料之外的行为,如以下例子所演示的: </P ><DIV CLASS="informalexample" ><P ></P ><A NAME="AEN3768" ></A ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br /></font><font color="#007700">function </font><font color="#0000BB">test_global_ref</font><font color="#007700">() {<br /> global </font><font color="#0000BB">$obj</font><font color="#007700">;<br /> </font><font color="#0000BB">$obj </font><font color="#007700">= &new </font><font color="#0000BB">stdclass</font><font color="#007700">;<br />}<br /><br />function </font><font color="#0000BB">test_global_noref</font><font color="#007700">() {<br /> global </font><font color="#0000BB">$obj</font><font color="#007700">;<br /> </font><font color="#0000BB">$obj </font><font color="#007700">= new </font><font color="#0000BB">stdclass</font><font color="#007700">;<br />}<br /><br /></font><font color="#0000BB">test_global_ref</font><font color="#007700">();<br /></font><font color="#0000BB">var_dump</font><font color="#007700">(</font><font color="#0000BB">$obj</font><font color="#007700">);<br /></font><font color="#0000BB">test_global_noref</font><font color="#007700">();<br /></font><font color="#0000BB">var_dump</font><font color="#007700">(</font><font color="#0000BB">$obj</font><font color="#007700">);<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ><P ></P ></DIV ><P > 执行以上例子会导致如下输出: </P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><PRE CLASS="screen" >NULL object(stdClass)(0) { }</PRE ></TD ></TR ></TABLE ><P > 类似的行为也适用于 <TT CLASS="literal" >static</TT > 语句。引用并不是静态地存储的: </P ><DIV CLASS="informalexample" ><P ></P ><A NAME="AEN3774" ></A ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><code><font color="#000000"> <font color="#0000BB"><?php<br /></font><font color="#007700">function &</font><font color="#0000BB">get_instance_ref</font><font color="#007700">() {<br /> static </font><font color="#0000BB">$obj</font><font color="#007700">;<br /><br /> echo </font><font color="#DD0000">'Static object: '</font><font color="#007700">;<br /> </font><font color="#0000BB">var_dump</font><font color="#007700">(</font><font color="#0000BB">$obj</font><font color="#007700">);<br /> if (!isset(</font><font color="#0000BB">$obj</font><font color="#007700">)) {<br /> </font><font color="#FF8000">// 将一个引用赋值给静态变量<br /> </font><font color="#0000BB">$obj </font><font color="#007700">= &new </font><font color="#0000BB">stdclass</font><font color="#007700">;<br /> }<br /> </font><font color="#0000BB">$obj</font><font color="#007700">-></font><font color="#0000BB">property</font><font color="#007700">++;<br /> return </font><font color="#0000BB">$obj</font><font color="#007700">;<br />}<br /><br />function &</font><font color="#0000BB">get_instance_noref</font><font color="#007700">() {<br /> static </font><font color="#0000BB">$obj</font><font color="#007700">;<br /><br /> echo </font><font color="#DD0000">'Static object: '</font><font color="#007700">;<br /> </font><font color="#0000BB">var_dump</font><font color="#007700">(</font><font color="#0000BB">$obj</font><font color="#007700">);<br /> if (!isset(</font><font color="#0000BB">$obj</font><font color="#007700">)) {<br /> </font><font color="#FF8000">// 将一个对象赋值给静态变量<br /> </font><font color="#0000BB">$obj </font><font color="#007700">= new </font><font color="#0000BB">stdclass</font><font color="#007700">;<br /> }<br /> </font><font color="#0000BB">$obj</font><font color="#007700">-></font><font color="#0000BB">property</font><font color="#007700">++;<br /> return </font><font color="#0000BB">$obj</font><font color="#007700">;<br />}<br /><br /></font><font color="#0000BB">$obj1 </font><font color="#007700">= </font><font color="#0000BB">get_instance_ref</font><font color="#007700">();<br /></font><font color="#0000BB">$still_obj1 </font><font color="#007700">= </font><font color="#0000BB">get_instance_ref</font><font color="#007700">();<br />echo </font><font color="#DD0000">"\n"</font><font color="#007700">;<br /></font><font color="#0000BB">$obj2 </font><font color="#007700">= </font><font color="#0000BB">get_instance_noref</font><font color="#007700">();<br /></font><font color="#0000BB">$still_obj2 </font><font color="#007700">= </font><font color="#0000BB">get_instance_noref</font><font color="#007700">();<br /></font><font color="#0000BB">?></font> </font> </code></TD ></TR ></TABLE ><P ></P ></DIV ><P > 执行以上例子会导致如下输出: </P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" CELLPADDING="5" ><TR ><TD ><PRE CLASS="screen" >Static object: NULL Static object: NULL Static object: NULL Static object: object(stdClass)(1) { ["property"]=> int(1) }</PRE ></TD ></TR ></TABLE ><P > 上例演示了当把一个引用赋值给一个静态变量时,第二次调用 <TT CLASS="literal" >&get_instance_ref()</TT > 函数时其值并没有被<SPAN CLASS="emphasis" ><I CLASS="emphasis" >记住</I ></SPAN >。 </P ></DIV ></DIV ><DIV CLASS="NAVFOOTER" ><HR ALIGN="LEFT" WIDTH="100%"><TABLE SUMMARY="Footer navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" ><A HREF="language.variables.predefined.html" ACCESSKEY="P" >上一页</A ></TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="index.html" ACCESSKEY="H" >起始页</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" ><A HREF="language.variables.variable.html" ACCESSKEY="N" >下一页</A ></TD ></TR ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" >预定义变量</TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="language.variables.html" ACCESSKEY="U" >上一级</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" >可变变量</TD ></TR ></TABLE ></DIV ></BODY ></HTML >