foreach循环和&$ value的引用

问题描述 投票:20回答:6

为什么空的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?

php arrays foreach
6个回答
12
投票

在第一个循环结束时,$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)。

这很令人困惑,但它甚至都不是特别的;这是完全按照应有的方式执行的代码。

更多信息:PHP: Passing by Reference


11
投票

这是一个名称冲突:第一个循环中引入的名称$ 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);

这不会改变你的阵列。


5
投票

即使在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


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
)

Example


说明

取自foreach()手册。 (见大红色方框)

即使在foreach循环之后,$ value和最后一个数组元素的引用仍然存在。建议通过unset()销毁它。

它基本上意味着:引用值&$value和数组中的最后一个元素/项,在本例中是4保持不变。要反击这个问题,你必须在使用后使用unset()值,否则它将保留在数组中作为其原始值(如果这是有道理的)。

您还应该阅读:How does PHP 'foreach' actually work?


4
投票

循环后你应该使用以下方法取消设置此引用:

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()不会给我们任何暗示。


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

© www.soinside.com 2019 - 2024. All rights reserved.