php - Why must I rewind IteratorIterator

498
$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() is true. I'm curious why it requires that rewind() be called. I imagine there's good reason for it, but I would have expected it to simply start iteration at whatever state it's inner iterator is in, and leave it as an option to rewind before beginning iteration.

calling next() also seems to put it in a "valid" state(although it advances to the next position, suggesting it was previously at 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(), despite the inner iterator being in a valid state.

65

Answer

Solution:

With a fresh iterator the position isn't initialized, simply for performance reason, you can stack iterators on top of other iterators, if all of them would rewind during construction there would be some performance impact, additionally some iterators might change their first value after the constructor was executed - which is unknown to iterators further out.

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

744

Answer

Solution:

While extending theIteratorIterator class to spare implementing the whole iterator interface and/or to create a decorator of an iterator I've been running into this as well.

That decorator is already the solution to the problem, it only needs to implement the missing functionality to remove the inconsistency. No need for an auto-rewind:

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

Example: If you have anIterator object that is valid by default, e.g.ArrayIterator:

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

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

This shows the inconsistency of theIteratorIterator implementation well, theIteratorIterator object does not properly reflect the innerArrayIterator's state. Using theIteratorDecorator can heal this:

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

And if you have followed up until here, here is another special case you might want to consider: If you don't need to haverewind with the inner iterator, you can just use theNoRewindIterator which returns the validity correct as well:

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

Taken Johannes "no auto-rewind" arguments into account, this makes sense, as theNoRewindIterator expects that the iterator should not be rewinded and shows the inner iterator's validity correctly.

But as theIteratorDecorator shows, I don't do any kind of auto-rewind as well to remove the inconsistency.

290

Answer

Solution:

Like @johannes said, the position isn't initialized in theIteratorIterator and thus it is not valid before any other of it's methods are run on it or it is used with foreach()

Try to do

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

And also

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

And also note that on an unitiliazed IteratorIterator:

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

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

Hope that shed some light.

People are also looking for solutions to the problem: php - How can I connect to MySQL on a WAMP server?

Source

Didn't find the answer?

Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.

Ask a Question

Write quick answer

Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.

Similar questions

Find the answer in similar questions on our website.