RecursiveIteratorIterator返回额外的元素

Bab*_*aba 8 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();
}
Run Code Online (Sandbox Code Playgroud)

产量

AABC  <--- Instead of ABC
Run Code Online (Sandbox Code Playgroud)
  • 为什么额外A没有 C
  • 从未启动或调用Array为什么$iterator->rewind()while循环需要
  • foreach完美的工作,而不必调用使用迭代器rewind之间foreach和之间的差异while

代码在行动

Nik*_*kiC 5

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

foreach完美的工作,而不必调用rewind那些foreachwhile使用迭代器之间的差异

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

Array从未被启动或调用为什么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();
}
Run Code Online (Sandbox Code Playgroud)

这会产生以下输出:

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
Run Code Online (Sandbox Code Playgroud)

输出看起来有点奇怪,特别是第二次迭代错过了next()调用,所以它只停留在同一个元素上.

这样做的原因是实现的特殊性RecursiveIteratorIterator:迭代器在RS_START状态中启动,并且next此状态中的第一个调用仅检查hasChildren(),但实际上并不调用底层迭代器的next()方法.完成此操作后,它会切换到正确调用的RS_NEXT模式next().这就是向前推进一步的原因.

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