为什么一个空的foreach循环可以改变结果。
我有以下代码:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
var_dump($variable);
我得到的结果是:
array (size=4)
0 => int 2
1 => int 3
2 => int 4
3 => &int 5
现在,当我像这样添加一个空的foreach循环时:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
foreach ($variable as $key => $value);
var_dump($variable);
我明白了:
array (size=4)
0 => int 2
1 => int 3
2 => int 4
3 => &int 4
有人可以解释为什么当我添加第二个空循环时最后一个元素没有改变,为什么有一个&面前的最后一个元素?
答案 0 :(得分:12)
在第一个循环结束时,$value
指向与$variable[3]
相同的位置(它们指向内存中的相同位置):
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
即使此循环已完成,$value
仍然是指向内存中与$variable[3]
相同的位置的引用,因此每次在{{1}中存储值时},这也会覆盖为$value
存储的值:
$variable[3]
对每个foreach的每次评估,foreach ($variable as $key => $value);
var_dump($variable);
和$value
都变得等于$ variable中可迭代项的值。
因此,在第二个循环的第3次迭代中,$variable[3]
和$value
通过引用变为等于4,然后在第二次循环的第4次和最后一次迭代期间,没有任何变化,因为你'将$variable[3]
(仍为$variable[3]
)的值重新传递给&$value
(仍为$value
)。
这很令人困惑,但它甚至没有一点特殊性;它是正确执行 的代码。
此处有更多信息:PHP: Passing by Reference
答案 1 :(得分:11)
这是一个名称冲突:第一个循环中引入的名称$值存在于它之后,并在第二个循环中使用。因此,对它的所有赋值实际上都是对原始数组的赋值。您在此代码中更容易观察到您所做的事情:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
$value = 123; // <= here you alter the array!
var_dump($variable);
您会看到$variable[3]
为123
。
正如其他人所说,避免这种情况的一种方法是在循环之后unset ($value)
,这应该是手册推荐的一个好习惯。另一种方法是在第二个循环中使用另一个变量:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
foreach ($variable as $key => $val);
var_dump($variable);
不会改变你的数组。
答案 2 :(得分:5)
即使在foreach循环之后,数组的最后一个元素也会重新启动。所以它需要在循环之外使用unset
函数。那就是
$variable = [1,2,3,4];
foreach ($variable as $key => &$value) {
$value++;
}
unset($value);
var_dump($variable);
找到手册的链接
答案 3 :(得分:4)
As phil
stated in the comments:
如手册中所述,您应该在使用后取消设置()引用。
$variable = [1,2,3,4];
foreach ($variable as $key => &$value) {
$value ++;
}
unset($value);
foreach ($variable as $key => $value);
print_r($variable);
将返回:
Array
(
[0] => 2
[1] => 3
[2] => 4
[3] => 5
)
<强>解释强>
取自foreach()
手册。 ( 见大红框 )
$ value的引用和最后一个数组元素仍然保留在 foreach循环。建议通过unset()来销毁它。
它基本上意味着:引用的值&$value
和数组中的最后一个元素/项(在本例中为4
)保持不变。要反击此问题,您必须在使用后unset()
值,否则它将保留在数组中作为其原始值(如果有意义)。< / p>
答案 4 :(得分:4)
循环后,您应该使用以下方法取消设置此引用:
unset($value);
所以你的整个代码应该像这样工作:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value) {
$value++;
}
unset($value);
var_dump($variable);
将unset($value);
置于循环
解释 - 在循环之后,$ value仍设置为数组的最后一个元素,因此您可以在循环$value = 10;
之后(在取消设置之前)使用,并且您将看到数组的最后一个元素已更改为{{1 }}。似乎10
想要在这种情况下帮助我们,并显示最后一个元素的参考,当然,当我们使用var_dump
时,我们需要unset
的输出。
您还可以查看以下脚本:
var_dump
我们不在这里使用循环,如果引用设置为数组元素,<?php
$array = [1, 2, 3, 4];
var_dump($array);
$x = &$array[2];
var_dump($array);
$x += 20;
unset($x);
var_dump($array);
?>
会向我们显示此var_dump
这个元素的类型之前。
但是,如果上面的代码我们更改了引用并以这种方式设置&
var_dump将不会向我们显示任何引用。
同样在以下代码中:
$x = &$array;
<?php
$x = 23;
$ref = &$x;
var_dump($x);
?>
没有给我们任何暗示。
答案 5 :(得分:3)
强制性陈述:参考资料是邪恶的!
单步执行代码:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value++;
循环完成后; $value
是对$variable[3]
的引用,因此其值为int(4)
。
foreach ($variable as $key => $value);
在每次迭代时,$variable[3]
会被分配$variable[<k>]
元素0 <= k < 3
。在最后一次迭代中,它被赋值给它自己的值,这是前一次迭代的值,所以它是int(4)
。
在两个循环之间取消设置$value
可以解决这种情况。另见我的an earlier answer。