RecursiveIteratorIterator returns extra elements

iterator, php

Solution

I'm going to answer the questions in reverse order:

`foreach` works perfectly without having to call `rewind` whats the differences between those `foreach` and `while` when working with iterators

`foreach` internally does a call to `rewind()`, that's why you don't have to do it yourself. This is always done, so even if you have already used an iterator, the `foreach` loop will start over from the beginning. (You can avoid this by wrapping it in a `NoRewindIterator`).

The Array has never been initiated or called why is $iterator->rewind() required for while loop

The SPL iterators are designed to be used with `foreach` and to avoid duplicate method calls in this case. If the `RecursiveIteratorIterator` would call the `RecursiveArrayIterator::rewind()` method on construction, then it would be called again when the `foreach` loop starts. That's why the call isn't done.

Why an extra A not C ?

To figure this out it is nice to see which methods of the `RecursiveArrayIterator` actually get called:

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

This produces the following output:

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

The output looks a bit odd, in particular the second iteration misses the `next()` call, so it just stays at the same element.

The reason for this is a peculiarity in the `RecursiveIteratorIterator` implementation: Iterators start off in the `RS_START` state and the first `next` call in this state only checks `hasChildren()`, but does not actually call the underlying iterator's `next()` method. After this was done it switches into the `RS_NEXT` mode in which the `next()` call happens properly. That's why the forward move is delayed by one step.

In my eyes this is a bug, but https://bugs.php.net/bug.php?id=44063 claims otherwise.

Problem

`RecursiveIteratorIterator` returns extra result if `rewind()` is not called before `while` loop Example ``` $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(); } ``` Output ``` AABC <--- Instead of ABC ``` - Why an extra `A` not `C` ? - The Array has never been initiated or called why is `$iterator->rewind()` required for while loop - `foreach` works perfectly without having to call `rewind` whats the differences between `foreach` and `while` when working with iterators Code In action

Original source