问题一
我们先来看一段代码:
$a=[1,2,3];
foreach($a as &$v){
}
foreach($a as $v){
}
var_dump($a);
我们来看一下运行结果是什么
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(2)
}
是不是和大家想的不一样。
我们注意到运行结果里面,数组的最后一个元素是带有引用,这就是出现这样结果的关键所在。
让我们来分析一下运行过程,当程序运行完第一个循环之后,由于循环的变量$v
是引用类型,而在循环结束之后,变量 $v
会被保留下来,并且作为引用类型指向数组 $a
的最后一个元素。这样在执行第二个循环的时候,会将 $a[0]
、$a[1]
的值依次赋值给 $v
, 也即 $a[2]
。所以在最后一次循环之前,$a[2]
的值变成了 2。而最后一次循环的时候,并不会改变 $a[2]
的值,这样就得到了上面的结果。
总结
造成以上结果的主要原因是,如果循环使用的变量是引用类型的话,循环结束,这个变量会作为引用变量被保留下来,并且指向循环变量的最后一个元素。所以在循环外修改这个变量的话,会影响循环变量最后一个元素的值。
因此在写代码的时候,如果循环使用的变量是引用类型的话,在循环结束可以对变量进行 unset
操作,这样就不会有这样的问题了。
问题二
让我们再来看一段代码
$a=[1,2,3];
foreach($a as $v){
$a[2] = 0;
var_dump($a);
var_dump($v);
}
让我们来看一下运行结果
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(0)
}
int(1)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(0)
}
int(2)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(0)
}
int(3)
然我們稍微改一下代码
$b = &$a[2];
foreach($a as $v){
$b = 0;
var_dump($a);
var_dump($v);
}
运行结果如下
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(0)
}
int(1)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(0)
}
int(2)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(0)
}
int(0)
看出来不同了么?
对于第一段代码 Demo,在数组循环开始之后,在循环中修改数组的值不会影响循环;而如果有引用变量指向数组的元素,在循环中修改引用变量的值则会影响循环。