RecursiveIteratorIterator返回额外的元素

时间:2012-11-25 21:51:27

标签: php iterator

如果在RecursiveIteratorIterator循环

之前未调用rewind(),则

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
  • 为什么额外的A不是C
  • 数组从未启动或调用为什么while循环
  • 需要$iterator->rewind()
  • foreach完美无缺,无需在使用迭代器时调用rewindforeach之间的差异

Code In action

1 个答案:

答案 0 :(得分:5)

我将以相反的顺序回答问题:

  

foreach完美无缺,无需在使用迭代器时调用rewindforeach之间的差异{/ 1}}

while在内部拨打foreach,这就是您不必自己动手的原因。这总是完成的,所以即使你已经使用了迭代器,rewind()循环也会从头开始。 (您可以通过将其包装在foreach中来避免这种情况。)

  

数组从未被启动或调用为什么while循环需要$ iterator-&gt; rewind()

SPL迭代器旨在与NoRewindIterator一起使用,并避免在这种情况下重复的方法调用。如果foreach在构造时调用RecursiveIteratorIterator方法,则在RecursiveArrayIterator::rewind()循环开始时将再次调用它。这就是呼叫没有完成的原因。

  

为什么额外的A不是C?

为了弄清楚这一点,很高兴看到foreach实际被调用的方法:

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();
}

输出看起来有点奇怪,特别是第二次迭代错过了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 调用,所以它只停留在同一个元素上。

这是next()实现的一个特点:迭代器从RecursiveIteratorIterator状态开始,而此状态下的第一个RS_START调用仅检查next,但实际上并没有调用底层迭代器的hasChildren()方法。完成此操作后,它会切换到next()模式,RS_NEXT调用正常。这就是向前推进一步的原因。

在我看来这是一个错误,但https://bugs.php.net/bug.php?id=44063声称不是。