【发布时间】:2013-01-15 23:59:05
【问题描述】:
我有几个关于在 foreach() 循环期间修改数组的问题。在下面的代码中,我遍历三个包含闭包/回调的数组并调用每个数组。在迭代过程中,我在每个数组的末尾附加了一个闭包,但有时 foreach() 似乎无法识别出数组的大小已更改,因此不会调用附加的闭包。
class Foo
{
private $a1 = array();
private $a2 = array();
public function f()
{
echo '<pre style="font-size: 20px;">';
echo 'PHP: ' . phpversion() . '<br><br>';
$this->a1[] = function() { echo 'a1 '; };
$this->a1[] = array($this, 'g');
foreach ($this->a1 as &$v)
{
// The callback added in g() never gets called.
call_user_func($v);
//echo 'count(v) = ' . count($v) . ' ';
}
echo '<br>';
// The same thing works fine with a for() loop.
$this->a2[] = function() { echo 'a2 '; };
$this->a2[] = array($this, 'h');
for ($i = 0; $i < count($this->a2); ++$i)
call_user_func($this->a2[$i]);
echo '<br>';
// It also works fine using a local array as long as it
// starts off with more than one element.
$a3[] = function() { echo 'a3 '; };
//$a3[] = function() { echo 'a3 '; };
$i = 0;
foreach ($a3 as &$x)
{
call_user_func($x);
if ($i++ > 1) // prevent infinite loop
break;
// Why does this get called only if $a3 originally starts
// with more than one element?
$a3[] = function() { echo 'callback '; };
}
echo '</pre>';
}
private function g()
{
echo 'g() ';
$this->a1[] = function() { echo 'callback '; };
}
private function h()
{
echo 'h() ';
$this->a2[] = function() { echo 'callback '; };
}
}
$foo = new Foo;
$foo->f();
输出:
PHP: 5.3.14-1~dotdeb.0
a1 g()
a2 h() callback
a3
预期输出:
a1 g() callback
a2 h() callback
a3 callback
如果我取消注释循环前的第二个元素,$a3 的输出:
a3 a3 callback
- 为什么第一个循环
foreach ($this->a1 as &$v)没有意识到$v有另一个元素要迭代? - 为什么在第三个循环
foreach ($a3 as &$x)期间修改$a3有效,但仅当数组以多个元素开始时才有效?
我意识到在迭代期间修改数组可能不是一个好主意,但由于 PHP 似乎允许这样做,我很好奇为什么上面的工作方式如此。
【问题讨论】:
-
首先,您正在修改数组,同时它正在循环,而 PHP 的设计确实没有考虑到这一点。您最好在循环中执行回调函数并使用 foreach 而不引用。
-
@Hiroto 手册中提到了它,所以我认为 PHP 的设计考虑到了这一点。但是我意识到这可能不是一个好习惯,但我仍然想知道为什么它的行为如此,似乎不一致。
-
我创建了一个快速课程,基本上完成了您的课程并得出了相同的结果。根据 php foreach 页面,
while (list(, $value) = each($arr))应该与 foreach 完全相同,但是在使用 while 循环而不是 foreach 时我没有*问题。 -
它提到它是因为它可以完成,但是 PHP 的
foreach旨在复制数组并对其进行迭代,因为您不会以这种方式陷入无限循环。正如Rasmus Lerdorf 所说:“丑陋的问题往往需要丑陋的解决方案。以纯粹的方式解决丑陋的问题非常困难。”。 “优雅”的解决方案可能会使用回调函数,而不是依赖数组。