代码如下:
<code>$a = [1, 2, 3]; foreach($a as $key => &$value) { $value = 5; } var_dump($a);</code>
最后输出结果如下:
<code>array(3) { [0]=> int(5) [1]=> int(5) [2]=> &int(5) }</code>
问题:为什么会在最后的键值前出现取地址符?
代码如下:
<code>$a = [1, 2, 3]; foreach($a as $key => &$value) { $value = 5; } var_dump($a);</code>
最后输出结果如下:
<code>array(3) { [0]=> int(5) [1]=> int(5) [2]=> &int(5) }</code>
问题:为什么会在最后的键值前出现取地址符?
这个var_dump里出现的&代表你可以用一个其他的变量来改变它的值。
比如你这样
<code class="php">$b = &$a[0]; var_dump($a);</code>
这里打印的时候就会在第一个键值里出现&符号,表示你可以用其他变量($b)来更改它的值。
先来了解一下&
的基本用法。
<code class="php">$b = $c = 1; $a = &$b; $a = 2; echo "b=$b,c=$c\n"; $a = &$c; $a = 100; $a = 200; echo "b=$b,c=$c\n"; unset($a); $a = 500; echo "b=$b,c=$c\n";</code>
上面$a指定成$b的引用之后,除非再次指定成其他引用,或者unset($a),否则改变$a就是改变对应的$b的值。
对于你这个foreach,也是同样的道理,你把循环单步拆开,就是这个样子:
<code class="php">$value = &$a[0]; $value = 5; $value = &$a[1]; $value = 5; $value = &$a[2]; $value = 5;</code>
循环运行到最后的时候,$value是$a[2]的引用,所以就相当于这么个形式:
<code class="php">$a[0] = 5; $a[1] = 5; $value = &$a[2]; $a[2] = 5; var_dump($a);</code>
也就不难理解为什么var_dump会在最后的键值对上打印出一个&的符号了吧。
一般情况下这个不会导致什么大问题,只不过由于foreach的作用域问题,会导致在循环退出之后$value依旧可以使用,所以会出现一些匪夷所思的bug。
比如这样
<code class="php">$a = [1, 2, 3]; foreach($a as $key => &$value) { $value = $value+5; } var_dump($a); // [6,7,8] foreach($a as $value){} var_dump($a); // [6,7,7]</code>
加了一句空的foreach之后,反而导致$a变的不合理了,这个bug匪夷所思,原因也是因为那个空foreach里的$value是最上面那个&a[2]的引用。
那个空foreach相当于这样:
<code class="php">$value = &$a[2]; $value = $a[0]; $value = $a[1]; $value = $a[2];</code>
注意到了么,由于$value是$a[2]的引用,所以上面的改写一下就是这样:
<code class="php">$a[2] = $a[0]; $a[2] = $a[1]; $a[2] = $a[2];</code>
空foreach里在不停的改变$a[2],而由于$a[2]已经变成$a[1]的值了,所以$a[2] = $a[2];没有任何影响,值还是$a[1];
这种匪夷所思的bug是由于$value这个变量的作用域导致的,所以要么改个名,要么先把$value给unset掉。
<code class="php">$a = [1, 2, 3]; foreach($a as $key => &$value) { $value = $value+5; } var_dump($a); // 要么unset unset($value); // 要么foreach里不要用上面同名的$value,改为$value2222 foreach($a as $value2222){} var_dump($a);</code>
首先我想说,这是一个非常非常好的问题。我相信题主并不是分不清引用与非引用。
我先做了一下两个测试:
<code>$a = [1, 2, 3]; foreach($a as $key => &$value) { $value = 5; } foreach($a as $key => $value) { $value = 6; } var_dump($a);</code>
你猜输出是什么?
<code>array(3) { [0]=> int(5) [1]=> int(5) [2]=> &int(6) }</code>
另外一个测试是:
<code>$a = [1, 2, 3]; foreach($a as $key => &$value) { $value = 5; } foreach($a as $key => $value2) { $value2 = 6; } var_dump($a);</code>
这次的输出就看上去正常多了:
<code>array(3) { [0]=> int(5) [1]=> int(5) [2]=> &int(5) }</code>
所以说,这个问题应该是php全局变量的一个坑。