我有一些关于在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& $v)实现$v有另一个元素可以迭代?
>为什么在第三个循环foreach($a3 as& $x)中修改$a3工作,但只有当数组从多个元素开始时?
1.Why doesn’t the first loop foreach ($this->a1 as &$v) realise $v has another element to iterate over?
行为看起来是由于内部指针在每个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 <br/>'; }; $this->a1[] = array($this,'g'); foreach ($this->a1 as $key => &$v) { //lets get the key that the internal pointer is pointing to // before the call. $intPtr = (key($this->a1) === null) ? 'null' : key($this->a1); echo 'array ptr before key ',$key,' func call is ',$intPtr,'<br/>' ; call_user_func($v); //echo 'count(v) = ' . count($v) . ' '; } echo '<br><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><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() <br>'; $this->a1[] = function() { echo 'callback '; }; } private function h() { echo 'h() <br>'; $this->a2[] = function() { echo 'callback '; }; } } $foo = new Foo; $foo->f();
输出:
array ptr before key 0 func call is 1 a1 array ptr before key 1 func call is null <-will not iterate over any added elements! g() a2 h() callback a3
2.Why does modifying $a3 work during the third loop foreach ($a3 as &$x),but only when the array starts off with more than one element?
当然,如果在内部指针返回null之前向数组添加元素,那么元素将被迭代.在你的情况下,如果数组有一个元素,那么在第一次迭代中,内部指针已经返回null.然而,如果最初有多个元素,则可以在第一次迭代时添加附加元素,因为内部指针此时将指向第二个初始元素.