Why should I rewind IteratorIterator

$arrayIter = new ArrayIterator( array(1, 2) ); $iterIter = new IteratorIterator($arrayIter); var_dump($iterIter->valid()); //false var_dump($arrayIter->valid()); //true 

If I first call $ iterIter-> rewind (), then $ iterIter-> valid () will be true. I am curious why this requires a rewind () call. I suppose there is a good reason for this, but I would expect it to just start iterating in whatever state the internal iterator is in, and leave it as an opportunity to rewind before starting the iteration.

calling next () also seems to put it in the “correct” state (although it moves on to the next position, assuming it was previously in the first position).

 $arrayIter = new ArrayIterator(array(1,2)); $iterIter = new IteratorIterator($arrayIter); $iterIter->next(); var_dump($iterIter->valid()); 

Again, I'm curious why I need to call rewind (), even though the internal iterator is in a valid state.

+1
iterator php spl
source share
3 answers

With a new iterator, the position is not initialized, just for performance reasons, you can stack iterators on top of other iterators, if all of them are rewound during construction, there will be some impact on performance, in addition, some iterators can change their first value after the constructor is executed - which unknown to iterators further.

Iterators are usually executed by foreach (), which first rewind () ...

+5
source share

Extending the IteratorIterator class to get rid of the implementation of the entire iterator interface and / or to create an iterator decorator, I also came across this.

This decorator is already a solution to the problem, he only needs to implement the missing functionality to eliminate inconsistency. No need to rewind:

 class IteratorDecorator extends IteratorIterator { public function valid() { return $this->getInnerIterator()->valid(); } } 

Example. If you have an Iterator object that is valid by default, for example. ArrayIterator :

 $it = new ArrayIterator(array(1)); var_dump($it->valid()); # bool(true) $itit = new IteratorIterator($it); var_dump($itit->valid()); # bool(false) 

This indicates inconsistency in the implementation of the IteratorIterator implementation; the IteratorIterator object incorrectly reflects the internal state of the ArrayIterator . Using IteratorDecorator can fix this:

 $decor = new IteratorDecorator($it); var_dump($decor->valid()); # bool(true) 

And if you have traced so far, here is another special case that you can consider: If you don't need to have rewind with an internal iterator, you can simply use NoRewindIterator , which returns the correctness as well:

 $noretit = new NoRewindIterator($it); var_dump($noretit->valid()); # bool(true) 

Johannes’s “no automatic rewind” arguments make sense because NoRewindIterator expects the iterator to not rewind and correctly displays the correctness of the internal iterator.

But, as IteratorDecorator shows, I also do not automatically rewind to remove inconsistency.

+2
source share

Like @johannes, the position is not initialized in IteratorIterator and, therefore, it is not valid before any of its other methods are launched on it or it is used with foreach ()

Try to do

 var_dump( $iterIter->current() ); // NULL var_dump( $iterIter->getInnerIterator()->current() ); // 1 

And

 $iterIter->rewind(); var_dump( $iterIter->current() ); // 1 var_dump( $iterIter->getInnerIterator()->->current() ); // 1 

And also note that on the unified Iterator Iterator:

 $iterIter->next(); // 2 var_dump( $iterIter->current()) ; // 2 (from NULL to 2) var_dump( $iterIter->getInnerIterator()->current() ); // 2 

Note that the $arrayIter from your code snippet is identical to $iterIter->getInnerIterator() .

Hope to shed light.

0
source share

All Articles