foreach中的PHP按引用传递

foreach中的PHP按引用传递,php,Php,我有以下代码: $a = array ('zero','one','two', 'three'); foreach ($a as &$v) { } foreach ($a as $v) { echo $v.PHP_EOL; } 有人能解释为什么输出是: 零一二二 来自zend认证研究指南。因为在第二个循环中,$v仍然是最后一个数组项的引用,所以每次都会覆盖它 你可以这样看: $a = array ('zero','one','two', 'three'); foreach

我有以下代码:

$a = array ('zero','one','two', 'three');

foreach ($a as &$v) {

}

foreach ($a as $v) {
  echo $v.PHP_EOL;
}
有人能解释为什么输出是: 零一二二


来自zend认证研究指南。

因为在第二个循环中,
$v
仍然是最后一个数组项的引用,所以每次都会覆盖它

你可以这样看:

$a = array ('zero','one','two', 'three');

foreach ($a as &$v) {

}

foreach ($a as $v) {
  echo $v.'-'.$a[3].PHP_EOL;
}

如您所见,最后一个数组项接受当前循环值:“零”、“一”、“二”,然后它就是“二”…:)

因为如果创建对变量的引用,该变量的所有名称(包括原始名称)都将成为引用

我不得不花几个小时来弄清楚为什么[3]在每次迭代中都会发生变化。这就是我到达的原因

PHP中有两种类型的变量:普通变量和引用变量。如果我们将一个变量的引用分配给另一个变量,该变量将成为一个引用变量

例如在

$a = array('zero', 'one', 'two', 'three');
如果我们这样做

$v = &$a[0]
$v = &$a[1]
第0个元素(
$a[0]
)成为参考变量
$v
指向该变量;因此,如果我们对
$v
进行任何更改,它将反映在
$a[0]
中,反之亦然

现在如果我们这样做了

$v = &$a[1]
$a[1]
将成为一个参考变量,
$a[0]
将成为一个普通变量(因为没有其他人指向
$a[0]
它被转换为一个普通变量。PHP足够聪明,可以在没有其他人指向它时将其作为一个普通变量)

这就是第一个循环中发生的情况

foreach ($a as &$v) {

}
在最后一次迭代之后,
$a[3]
是一个参考变量

由于
$v
指向
$a[3]
$v
的任何更改都会导致对
$a[3]
的更改

在第二个循环中

foreach ($a as $v) {
  echo $v.'-'.$a[3].PHP_EOL;
}
在每次迭代中,
$v
改变,
$a[3]
改变。(因为
$v
仍然指向
$a[3]
)。这就是为什么
$a[3]
每次迭代都会发生变化的原因

在最后一次迭代之前的迭代中,
$v
被赋值为“2”。由于
$v
指向
$a[3]
$a[3]
现在获得值“2”。记住这一点


在上一次迭代中,
$v
(指向
$a[3]
)现在的值为'two',因为在上一次迭代中将
$a[3]
设置为2<已打印代码>两个。这解释了为什么在最后一次迭代中打印$v时重复“2”

我发现这个例子也很棘手。为什么在最后一次迭代的第二个循环中什么也没发生($v保持“2”),是因为$v指向$a[3](反之亦然),所以它不能给自己赋值,所以它保留了以前分配的值:)

第一个循环

$v=$a[0];
$v=$a[1];
$v=$a[2];
$v=$a[3];
对!!当前
$v
=
$a[3]
位置

第二圈

$a[3]=$v=$a[0],echo$v;//与$a[3]和$a[0]=“零”相同
$a[3]=$v=$a[1],回显$v;//与$a[3]和$a[1]=“一”相同
$a[3]=$v=$a[2],回显$v;//与$a[3]和$a[2]=“2”相同
$a[3]=$v=$a[3],回显$v;//与$a[3]和$a[3]=“2”相同
因为在处理之前,
$a[3]
是由分配的。

这:

$a = array ('zero','one','two', 'three');

foreach ($a as &$v) {

}

foreach ($a as $v) {
    echo $v.PHP_EOL;
}

$a = array ('zero','one','two', 'three');

$v = &$a[3];

for ($i = 0; $i < 4; $i++) {
    $v = $a[$i];
    echo $v.PHP_EOL; 
}

我认为这段代码显示的过程更清楚

<?php

$a = array ('zero','one','two', 'three');

foreach ($a as &$v) {
}

var_dump($a);

foreach ($a as $v) {
  var_dump($a);
}

我只是偶然来到这里,OP的问题引起了我的注意。不幸的是,我不理解上面的任何解释。在我看来,似乎每个人都知道它,理解它,接受它,只是无法解释

幸运的是,上的PHP文档中的一句话完全说明了这一点:

警告:引用的
$value
和最后一个数组元素即使在foreach循环之后仍然保留。建议通过unset()将其销毁


这个问题提供了很多解释,但没有明确的例子说明如何解决这种行为导致的问题。在大多数情况下,您可能需要在passby-reference
foreach
中使用以下代码

foreach ($array as &$row) {
    // Do stuff
}
// Unset to remove the reference
unset($row);

unset($your\u used\u reference)每次使用
foreach($var as&$your\u used\u reference)
!谢谢你的观点,但我只是想了解第二个foreach的工作逻辑。为什么$your_used_reference(或者$v在OPs post中)不会自动取消设置?它的作用域是foreach,不应该存在于PHP中的@Hurix循环之外。现在的问题是。如果是这样,那么为什么在第二个循环中将$v更改为&$v会改变结果,即它回显0、1、2、3?因为当在第二个循环中使用&$v时,您正在更改变量的引用。这样,问题就消除了。好的,这意味着在最后一次迭代中,最后一项或保留两项,或再次分配两项,为什么不分配三项?为什么它在最后一次停止?:)它不会停止。最后一个数组项指定了当前循环值。所以它被分配为“零”,然后是“一”,然后是“二”。在上一次迭代中,由于上一次迭代,它被分配了自己的值,即“2”。所以它仍然是“两个”。在改进输出后,我能够理解:
$v获得项[0](零)$[3]现在为零$v获取项目[1](一)$a[3]现在是1$v获得项目[2](2)$a[3]现在是2$v获得项目[3](2)$a[3]现在是两个
,这太违反直觉了。在我看来,当循环离开时,$v将从内存中退出是有道理的。但事实就是这样。似乎是语言上的一个缺陷。在C中,我认为$v将超出循环之外的范围。@jamador PHP手册建议调用
unset($item)以避免此问题。我喜欢你的解释,但这仍然是让我经常困惑的事情之一。我必须记住要保持清醒才行。:-)对我来说,
参考变量
就是
参考
,在本例中是
$v
<代码>$a
array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(5) "three" } array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(4) "zero" } array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(3) "one" } array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(3) "two" } array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(3) "two" }
foreach ($array as &$row) {
    // Do stuff
}
// Unset to remove the reference
unset($row);