php手册之变量范围

手册目录: 语言参考---变量---变量范围

参考详情: https://secure.php.net/manual/zh/language.variables.scope.php

评论部分:

1. by warhog@warhog.net

提出一些有趣的代码,在类函数里面使用static变量,如:

<?php

class sample_class
{
  public function
func_having_static_var($x= NULL)
  {
    static
$var = 0;
    if (
$x === NULL)
    { return
$var; }
   
$var = $x;
  }
}

$a = new sample_class();
$b = new sample_class();
echo
$a->func_having_static_var()."\n";
echo
$b->func_having_static_var()."\n";
// this will output (as expected):
//  0
//  0

$a->func_having_static_var(3);
echo
$a->func_having_static_var()."\n";
echo
$b->func_having_static_var()."\n";
// this will output:
//  3
//  3
// maybe you expected:
//  3
//  0
?>

本来我们期望的可能是输出3.0,因为两个不同的实例,调用public非static方法,应该是互不干扰的.但是结果却告诉我们并非如此,方法中的static变量会作用于整个类方法以及所有的类实例,而不仅仅针对某一个实例.如果你想得到期望的输出,你应该放弃使用方法内static变量,像这样:

<?php
class sample_class
{ protected $var = 0;    //使用类内非static变量代替
  function
func($x= NULL)
  {
$this->var= $x; }
}

?>

我觉得正常的行为情况下是不应该像第一个例子那样使用static变量的,但也许你会用到(比如我),希望这些能对你有用.

你也可以通过类的实例来动态添加该实例的内部public变量,就像$instance->$param = $value 就会向$instance中动态添加了public的$param,当然这只针对该实例有效,不会对类及其他实例造成影响,其实该用法没什么卵用,只是想说php真特么强,笑尿.


2.by dodothedreamer@gmial.com

与java和C++不同的是,在循环块和if块语句中的变量可以在块外访问,如:

<?php
for($j=0;$j<3;$j++)
{
     if(
$j == 1)
       
$a = 4;
}
echo
$a;  //输出 4
?>

3. by Stephen Dewey

对于嵌套函数,global始终指明的是最外层的全局变量,而不是指上一层的范围,如下将不会按照预期输出:

<?php
// $var1 is not declared in the global scope
function a($var1){
    function
b(){
        global
$var1;
        echo
$var1; // there is no var1 in the global scope so nothing to echo
   
}
   
b();
}
a('hello');
?>

如果此时在function之上添加$var1 = 'some',将会得到输出结果'some'.

4. by emartin@sigb.net

如果你有一个php文件里声明了全局变量,当你在另一个文件的方法中包含这个php文件时,你将会发现包含进来的文件里的全局变量变成了只作用于方法内的局部变量,如下是解决办法:

main_file.php :
<?php
//Some innocent variables which exist before the problem
$a = 42;
$b = 33;
$c = 56;

function
some_function() {
   
//Some variables that we don't want out of the function
   
$saucisse = "saucisse";
   
$jambon = "jambon";
   
   
//Let's include another file
   
$evalt = "require_once 'anothertest_include.php';";
   
$before_eval_vars =get_defined_vars();
    eval(
$evalt);

   
//Let's extract the variables that were defined AFTER the call to 'eval'
   
$function_variable_names = array("function_variable_names"=> 0,"before_eval_vars" => 0, "created"=> 0);
   
//We can generate a list of the newly created variables by substracting the list of the variables of the function and the list of the variables which existed before the call to the list of current variables at this point
   
$created = array_diff_key(get_defined_vars(),$GLOBALS, $function_variable_names,$before_eval_vars);
   
//Now we globalize them
   
foreach ($created as $created_name =>$on_sen_fiche)
        global $
$created_name;
   
//And we affect them
   
extract($created);
}
some_function();
print_r(get_defined_vars());
?>

included_file.php :
<?php
//Some variables that we want in the global scope of main_file.php
$included_var_one = 123;
$included_var_two = 465;
$included_var_three = 789;
?>

如此,你将可以在some_function 之外访问global变量$included_var_one,two,three.同时需要注意的一点:

function test(){

  $a = 4;

  global $a;

}   //这样声明是错误的,必须先声明,所以正确的写法是将global $a放在$a = 4的前面.


5. by danno@wpi.edu

他提出一段有趣的代码,经过我的修正之后,大致如下:

<?php
class obj{
    public function __destruct(){
        echo 'destruct';
    }
}

function foo ()
{
   global $testvar;
   $localvar = new obj();
   $testvar = &$localvar;
}

foo ();
var_dump($testvar);  
?>

输出

destruct

NULL

因为对象引用是引用同一标识符,所以当方法结束后,相当于unset($localvar),此时没有其他标识符指向类实例,所以调用destruct,同时$testvar也相当于被unset了,为NULL,如果修改function如下:

function foo ()
{
   global $testvar;
   $localvar = new obj();
   $testvar = $localvar;  //此处将引用改为赋值
}

输出

object(obj)#1 (0) {
}
 destruct

可以看到,赋值跟引用是有区别的,赋值会copy一份标识符指向类实例,所以对$localvar的释放并不会影响$testvar,所以直到程序的最后才会调用destruct.

具体的赋值与引用的区别可以参见:http://segmentfault.com/a/1190000002928594


6. by jinxidoru@byu.net

关于类内方法使用static变量,1中已经提到过,这里指出,static变量不支持继承,如下:

<?php
class A {
    function
Z() {
        static
$count =0;       
       
printf("%s: %d\n",get_class($this), ++$count);
    }
}

class
B extends A {}
$a = new A();
$b = new B();
$a->Z();
$a->Z();
$b->Z();
$a->Z();
?>

输出:
A: 1
A: 2
B: 1
A: 3

可以看到,类A和类B使用了不同的静态变量,即使他们使用的是同一个方法,而且就算function Z是静态方法,结果也是一样.


7. by moraesdno@gmail.com

这里提一下,使用超全局$GLOBALS数组比使用global关键字更快.

8. by Anonymous

Anonymous提出如果static变量是一个数组,并且返回它的某个元素的时候,会返回该元素的引用,于是有了如下的测试代码:

<?php
function incr(&$int) {
  return
$int++;
}

function
return_copyof_scalar() {
  static
$v;
  if (!
$v)  
   
$v = 1;
  return(
$v);
}

function
return_copyof_arrayelement() {
  static
$v;
  if (!
$v) {
   
$v = array();
   
$v[0] =1;
  }
  return(
$v[0]);
}

echo
"scalar: ".
    
incr(return_copyof_scalar()).
    
incr(return_copyof_scalar()).
    
"\n";
echo
"arrayelement: ".
    
incr(return_copyof_arrayelement()).
    
incr(return_copyof_arrayelement()).
    
"\n";
?>

期望输出:

scalar:11

array element:11

他测试的结果:

scalar:11

array emelent:12

但是我在php7上进行了同样的测试,发现结果跟期望输出是一样的,所以这里的数组元素并没有按照引用返回,如果我们要使用引用,应该像&function这样声明函数,也需要像&function一样调用它,但是有一个例外,就是当incr(return_copyof_scalar())这样作为参数调用的时候,不需要添加&,如此只需要在上述例子中的函数声明部分各自添加&就可以得到输出结果:

scalar:12

array element:12


9. by info@SyPlex.net

有时候你需在在其他多个函数中访问同一个static,同时这个static的可见范围也是非全局的,这里有一个简单的方法解决这个问题:

<?php
 
// We need a way to get a reference of our static
 
function &getStatic() {
    static
$staticVar;
    return
$staticVar;
  }
 
// Now we can access the static in any method by using it's reference
 
function fooCount() {
   
$ref2static = & getStatic();
    echo
$ref2static++;
  }
 
fooCount(); // 0
 
fooCount(); // 1
 
fooCount(); // 2
?>

10. by Jack@soinsincere.com

你不可以将方法里的static与传入进来的引用参数关联,但是你可以使用数组的形式对引用进行保存与操作,如下:

<?php
function test($arr = null){
    static $my;
    if(!$arr)return $my[0];
    $my = $arr;
}

$you = 'hello';
test(array(&$you));
$you = 'world';
var_dump(test());
?>
输出 world

再考虑我自己添加的一段代码:

<?php
function tst(&$test){
    static $num = 0;
    static $t = 2;
    if($num != 0){
        var_dump($t);
    }
    $t = &$test;
    $t = 3;
    $num++;
}

$a = 1;
tst($a);
tst($a);
?>
预期输出1或者3

实际输出 2  可以这样推断,static在堆中有一个固定的内存块,在function中第一次赋值为2的时候,该内存块就保存了2的值,之后的一系列引用,赋值修改操作只是将static当做一个指针使用,当function执行完之后,static还是回归指向堆中固定的那块内存,所以,如果之前的一系列操作没有对该固定内存进行值修改,下次再访问static的时候,依然会是之前的值2,而不是预期的指向新的内存地址,所以当使用array数组保存引用并将array保存到static的固定内存块中,才会对下次的static调用造成影响,进而访问到array中保存的引用.个人愚见,有错误的地方还请指正.


11. by ppo@beeznest.net

即使某个被include进来的file使用return返回一个value,该value仍然与include的文件中的同名value保持同一个访问范围,如:

<?php
$foo
= 'aaa';
$bar = include('include.php');
echo(
$foo.' / '.$bar);
?>

where include.php is
<?php
$foo
= 'bbb';
return
$foo;
?>

期望输出:aaa/bbb

实际输出:bbb/bbb


12. by mod

mod提出一个比较有意思的代码,如下:

<?php
 
class A
  
{
     function
__destruct()
      {
        global
$g_Obj;
        echo
"<br>#step 2: ";
       
var_dump($g_Obj);
      }

     function
start()
      {
        global
$g_Obj;
        echo
"<br>#step 1: ";
       
var_dump($g_Obj);
      }
   };

 
$g_Obj = new A();       // start here
 
$g_Obj->start();

?>

mod得到的输出是:

#step 1: object(A)#1 (0) { }
#step 2: object(A)#1 (0) { }

但是我在php7上测试的结果是:

#step 1: object(A)#1 (0) { }
#step 2: NULL

可以知道,php中class的destruct最先操作的是将类实例变量置为空值,然后再调用destruct里面的代码.为了证明这一点,我们可以在上述的例子最后添加一句代码:

$g_Obj = true

得到的输出将变成:

#step 1: object(A)#1 (0) { }
#step 2:
bool(true)


13. by huntsbox@pacbell.net

嵌套函数需要注意重复声明以及第一次声明,如下例子:

<?php
function norm($a, $b) {
    static $first_time = true;
    if($first_time) {
        function square($x)
        {
            return $x * $x;
        }
        $first_time = false;
    }
    return sqrt(square($a) + square($b));
}

print norm(5,4);
print "<br>";
print square(4);
print "<br>";
print norm(6,5);
print "<br>";
?>
该例子能正确输出结果,如果将function中的判断语句if($first_time)去掉,就会造成重复声明的错误,同时,如果 在语句print norm(5,4)之前调用square函数,将会导致undefined function 的错误,必须先执行一遍外部的norm函数,告诉外部存在其内部定义声明的square函数.


14. by tomek@pluton.pl

当定义一个static变量时,你可以这样声明:

<?php
static $var =1; //numbers
static $var ='strings';
static
$var = array(1,'a',3);//array construct
?>
但是你不可以这样声明(error):

<?php
static $var =some_function('arg');
static
$var = (some_function('arg'));
static
$var = 2+3;//any expression
static $var = newobject;
?>


15. by jochen_burkhard@web.de

jochen提出当使用远程调用php文件时,远程文件中的变量将不能在调用文件中使用,如;

remotefile.php:
<?PHP
$paramVal
=10;
?>

localfile.php:
<?PHP
include "http://example.com/remotefile.php";
echo
"remote-value= $paramVal";   //将不会得到预期值
?>
这里提一下,本人没有亲自测试过,需要的自己测试下真伪.


本人水平有限,如有错误的地方,请及时指正并及时改正.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值