php中 global/static 的一个小陷阱的解释

在php手册中,关于global/static变量有这么一段说明

在 Zend 引擎 1 代,它驱动了 PHP4,对于变量的 static 和 global 定义是以引用的方式实现的。例如,在一个函数域内部用 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);

上面这段代码的输出是:

NULL
object(stdClass)(0) {
}

很多人也许会纠结为什么第一个会是null,并且开始纠结是不是因为用了过时(并且从php7开始已经被移除)的特性Assigning the return value of new by reference所导致的。然而事实并非如此,让我们把上面这个例子稍作改动:

<?php
function test_global_ref() { 
    global $obj; 
    $b = 'xiami';
    $obj = &$b; 
} 
function test_global_noref() { 
    global $obj; 
    $b = 'xiami';
    $obj = $b; 
} 
test_global_ref(); 
var_dump($obj); 
test_global_noref(); 
var_dump($obj);

这是一个在目前最新的php(php 7.0.13)下依然可以无任何错误运行的一段代码,它的第一个输出的结果依然是null,为什么?

再回过头读一遍手册上的解释,在一个函数域内部用 global 语句导入的一个真正的全局变量实际上是建立了一个到全局变量的引用,换言之global $obj;$obj = &$GLOBALS['obj'];是完全等价的,那么上面的第一个方法就相当于

1
2
3
4
5
6
<?php
function test_global_ref() { 
    $obj = &$GLOBALS['obj'];
    $b = 'xiami';
    $obj = &$b; 
}

在PHP中,引用不是指针,因此第5行的代码只不过是将$obj在函数内重新绑定到了$b上,全局范围内的$obj的值没有任何变化,而因为一开始$obj并没有定义,所以自然就是null了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注