为什么空的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
有人可以解释一下为什么当我添加第二个空循环时最后一个元素不会改变,以及为什么最后一个元素有一个&infront?
在第一个循环结束时,$value
指向与$variable[3]
相同的位置(它们指向内存中的相同位置):
$variable = [1,2,3,4];
foreach ($variable as $key => &$value)
$value ++;
即使这个循环完成,$value
仍然是一个引用,它指向内存中与$variable[3]
相同的位置,因此每次在$value
中存储一个值时,这也会覆盖为$variable[3]
存储的值:
foreach ($variable as $key => $value);
var_dump($variable);
对每个foreach的评估,$value
和$variable[3]
都变得等于$ variable中可迭代项的值。
因此,在第二个循环的第3次迭代中,$value
和$variable[3]
通过引用变为等于4,然后在第二次循环的第4次和最后一次迭代期间,没有任何变化,因为你传递$variable[3]
(仍然是&$value
)的值$value
(仍然是&$value
)。
这很令人困惑,但它甚至都不是特别的;这是完全按照应有的方式执行的代码。
这是一个名称冲突:第一个循环中引入的名称$ value存在于它之后,并在第二个循环中使用。因此,对它的所有赋值实际上都是对原始数组的赋值。您在此代码中更容易观察到您所做的事情:
$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);
这不会改变你的阵列。
即使在foreach循环之后,数组的最后一个元素仍将保留。所以它需要在循环外部使用unset
函数。那就是
$variable = [1,2,3,4];
foreach ($variable as $key => &$value) {
$value++;
}
unset($value);
var_dump($variable);
手册的链接可以在这里找到http://php.net/manual/en/control-structures.foreach.php
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()
手册。 (见大红色方框)
即使在foreach循环之后,$ value和最后一个数组元素的引用仍然存在。建议通过unset()销毁它。
它基本上意味着:引用值&$value
和数组中的最后一个元素/项,在本例中是4
保持不变。要反击这个问题,你必须在使用后使用unset()
值,否则它将保留在数组中作为其原始值(如果这是有道理的)。
循环后你应该使用以下方法取消设置此引用:
unset($value);
所以你的整个代码应该像这样工作:
$variable = [1,2,3,4];
foreach ($variable as $key => &$value) {
$value++;
}
unset($value);
var_dump($variable);
把unset($value);
放在循环中是没有意义的
解释 - 在循环之后,$ value仍然设置为数组的最后一个元素,因此您可以在循环$value = 10;
(未设置之前)之后使用,并且您将看到数组的最后一个元素已更改为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
向我们展示了这个元素的类型之前的&
。
但是,如果上面的代码我们更改了引用并以这种方式设置它,$x = &$array;
var_dump将不会向我们显示任何引用。
同样在以下代码中:
<?php
$x = 23;
$ref = &$x;
var_dump($x);
?>
var_dump()
不会给我们任何暗示。
强制性声明:参考文献是邪恶的!
单步执行代码:
$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。