Php 递归迭代器返回额外的元素
Php 递归迭代器返回额外的元素,php,iterator,Php,Iterator,RecursiveIteratorIterator如果在之前未调用while循环,则返回额外结果 范例 $array = array("A","B","C"); $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array)); //$iterator->rewind() ; this would fix it while ( $iterator->valid() ) { print(
RecursiveIteratorIterator
如果在之前未调用while
循环,则返回额外结果
范例
$array = array("A","B","C");
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
//$iterator->rewind() ; this would fix it
while ( $iterator->valid() ) {
print($iterator->current()) ;
$iterator->next();
}
输出
AABC <--- Instead of ABC
AABC倒带()
while循环需要
foreach
在使用迭代器时,无需调用revind
foreach
和之间有什么区别
我将以相反的顺序回答问题:
foreach
在使用迭代器时,无需调用revind
即可完美工作foreach
和之间有什么区别
foreach
在内部调用revind()
,这就是为什么您不必自己做这件事。这通常是这样做的,因此即使您已经使用了迭代器,foreach
循环也将从头开始。(可以通过将其包装在norewindicator
中来避免这种情况)
该数组从未被启动或调用。为什么while循环需要$iterator->rewind()
SPL迭代器设计用于foreach
,并在这种情况下避免重复的方法调用。如果RecursiveIteratorIterator
在构造时调用RecursiveArrayIterator::rewind()
方法,那么当foreach
循环开始时,将再次调用它。这就是为什么电话没打完
为什么额外的A不是C
要了解这一点,很高兴看到实际调用了RecursiveArrayIterator
的哪些方法:
<?php
class DebugRAI extends RecursiveArrayIterator {
public function rewind() { echo __METHOD__, "\n"; return parent::rewind(); }
public function current() { echo __METHOD__, "\n"; return parent::current(); }
public function key() { echo __METHOD__, "\n"; return parent::key(); }
public function valid() { echo __METHOD__, "\n"; return parent::valid(); }
public function next() { echo __METHOD__, "\n"; return parent::next(); }
}
$array = array("A", "B", "C");
$iterator = new RecursiveIteratorIterator(new DebugRAI($array));
while ($iterator->valid()) {
echo $iterator->current(), "\n";
$iterator->next();
}
输出看起来有点奇怪,特别是第二次迭代错过了next()
调用,所以它只是停留在同一个元素上
原因是RecursiveIteratorIterator
实现中的一个特性:迭代器在RS\u start
状态下启动,此状态下的第一个next
调用仅检查hasChildren()
,而实际上不调用底层迭代器的next()
方法。完成此操作后,它将切换到RS\u NEXT
模式,在该模式下,NEXT()
调用将正常进行。这就是前进步伐被推迟一步的原因
在我看来,这是一个bug,但事实并非如此。它看起来像一个PHP bug。如果你有非常重要的原因知道它,并且这里没有人能够回答,那么试试你在ext/spl/spl_迭代器中的运气吧。cIt还有一些其他迭代器,调用valid()
会产生意想不到的结果,除非迭代器没有正确初始化,这既有调用\u construct()
,也有倒带()
在valid()之前调用。
可以被调用。如果你不能解决这个问题,你可以使用。如果你不调用rewind,迭代器的行为也会很奇怪。@rambocoder也观察到了这一点。。这看起来更像是一个错误。我把它放在一边,因为我的第一个直觉是,如果我在编写spl,我会对它进行编码(仅转发方法调用),可能有一个bool变量来缓存返回值。但是,当我开始考虑像CachingIterator
这样的东西时,整个迭代器/装饰器范式是否仍然可以与像recursiveiterator
这样的复杂迭代器一起工作,并且异常/错误是否会在疯狂的时刻抛出,这就太复杂了,无法思考一个问题不费吹灰之力的比赛。
DebugRAI::valid
DebugRAI::current
A
DebugRAI::valid
DebugRAI::valid
A
DebugRAI::next
DebugRAI::valid
DebugRAI::valid
DebugRAI::current
B
DebugRAI::next
DebugRAI::valid
DebugRAI::valid
DebugRAI::current
C
DebugRAI::next
DebugRAI::valid
DebugRAI::valid