我有这段代码:
$a = array ('zero','one','two', 'three');
foreach ($a as &$v) {
}
foreach ($a as $v) {
echo $v.PHP_EOL;
}
有人可以解释为什么输出是: 零一两。
来自zend认证学习指南。
答案 0 :(得分:154)
我不得不花费几个小时来弄清楚为什么[3]每次迭代都会发生变化。这是我到达的解释。
PHP中有两种类型的变量:正常变量和引用变量。如果我们将变量的引用分配给另一个变量,则该变量将成为引用变量。
例如在
中$a = array('zero', 'one', 'two', 'three');
如果我们这样做
$v = &$a[0]
第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
被赋值为'two'。由于$v
指向$a[3]
,$a[3]
现在获得值“2”。记住这一点。
在上一次迭代中,$v
(指向$a[3]
)现在具有值“2”,因为$a[3]
在上一次迭代中设置为2。打印two
。这解释了为什么在最后一次迭代中打印$ v时会重复“两个”。
答案 1 :(得分:133)
因为在第二个循环中,$v
仍然是对最后一个数组项的引用,所以每次都会覆盖它。
你可以这样看:
$a = array ('zero','one','two', 'three');
foreach ($a as &$v) {
}
foreach ($a as $v) {
echo $v.'-'.$a[3].PHP_EOL;
}
如您所见,最后一个数组项采用当前循环值:'zero','one','two',然后它只是'two'...... :)
答案 2 :(得分:49)
第一次循环
$v = $a[0];
$v = $a[1];
$v = $a[2];
$v = $a[3];
是的!当前$v
= $a[3]
位置。
第二次循环
$a[3] = $v = $a[0], echo $v; // same as $a[3] and $a[0] == 'zero'
$a[3] = $v = $a[1], echo $v; // same as $a[3] and $a[1] == 'one'
$a[3] = $v = $a[2], echo $v; // same as $a[3] and $a[2] == 'two'
$a[3] = $v = $a[3], echo $v; // same as $a[3] and $a[3] == 'two'
因为$a[3]
是在处理之前分配的。
答案 3 :(得分:16)
我偶然来到这里,OP的问题引起了我的注意。不幸的是,我不理解顶部的任何解释。对我来说似乎每个人都知道它,得到它,接受它,无法解释。
幸运的是,来自foreach的PHP文档的纯粹句子使这一点完全清楚:
警告:即使在foreach循环之后,
$value
和最后一个数组元素的引用仍然存在。建议通过unset()来销毁它。
答案 4 :(得分:15)
我认为此代码更清晰地显示了该过程。
<?php
$a = array ('zero','one','two', 'three');
foreach ($a as &$v) {
}
var_dump($a);
foreach ($a as $v) {
var_dump($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"
}
答案 5 :(得分:9)
这个问题提供了很多解释,但没有明确的例子说明如何解决这种行为导致的问题。在大多数情况下,您可能希望通过引用foreach
传递以下代码。
foreach ($array as &$row) {
// Do stuff
// Unset
unset($row);
}
答案 6 :(得分:4)
这:
$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;
}
OR
$a = array ('zero','one','two', 'three');
for ($i = 0; $i < 4; $i++) {
$a[3] = $a[$i];
echo $a[3].PHP_EOL;
}
OR
$a = array ('zero','one','two', 'three');
$a[3] = $a[0];
echo $a[3].PHP_EOL;
$a[3] = $a[1];
echo $a[3].PHP_EOL;
$a[3] = $a[2];
echo $a[3].PHP_EOL;
$a[3] = $a[3];
echo $a[3].PHP_EOL;
答案 7 :(得分:1)
我发现这个例子也很棘手。为什么在最后一次迭代的第二个循环中没有任何反应($ v保持'2'),是$ v指向$ a [3](反之亦然),所以它不能为自己赋值,所以它保留了先前的指定值:)
答案 8 :(得分:0)
因为如果您创建对变量的引用,则该变量的所有名称(包括原始名称)都是BECOME REFERENCES。