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
AnotC? - The Array has never been initiated or called why is
$iterator->rewind()required for while loop foreachworks perfectly without having to callrewindwhats the differences betweenforeachandwhilewhen working with iterators
I’m going to answer the questions in reverse order:
foreachinternally does a call torewind(), that’s why you don’t have to do it yourself. This is always done, so even if you have already used an iterator, theforeachloop will start over from the beginning. (You can avoid this by wrapping it in aNoRewindIterator).The SPL iterators are designed to be used with
foreachand to avoid duplicate method calls in this case. If theRecursiveIteratorIteratorwould call theRecursiveArrayIterator::rewind()method on construction, then it would be called again when theforeachloop starts. That’s why the call isn’t done.To figure this out it is nice to see which methods of the
RecursiveArrayIteratoractually get called:This produces the following output:
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
RecursiveIteratorIteratorimplementation: Iterators start off in theRS_STARTstate and the firstnextcall in this state only checkshasChildren(), but does not actually call the underlying iterator’snext()method. After this was done it switches into theRS_NEXTmode in which thenext()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.