为什么我必须回放IteratorIterator

时间:2010-03-16 23:34:59

标签: php iterator spl

$arrayIter = new ArrayIterator( array(1, 2) );
$iterIter = new IteratorIterator($arrayIter);

var_dump($iterIter->valid()); //false
var_dump($arrayIter->valid()); //true

如果我首先调用 $ iterIter-> rewind(),则 $ iterIter-> valid()为true。我很好奇为什么要调用rewind()。我想它有充分的理由,但我希望它只是在内部迭代器处于的任何状态下开始迭代,并在开始迭代之前将其作为倒带选项。

调用next()似乎也将其置于“有效”状态(虽然它前进到下一个位置,表明它之前位于第一个位置)。

$arrayIter = new ArrayIterator(array(1,2));
$iterIter = new IteratorIterator($arrayIter);

$iterIter->next();
var_dump($iterIter->valid()); 

同样,我很好奇为什么我需要调用rewind(),尽管内部迭代器处于有效状态。

3 个答案:

答案 0 :(得分:5)

使用新的迭代器,位置没有初始化,只是出于性能原因,你可以将迭代器堆叠在其他迭代器之上,如果所有这些迭代器在构造期间都会倒带会对性能产生影响,另外一些迭代器可能会改变它们的执行构造函数后的第一个值 - 对于迭代器来说是未知的。

迭代器通常由foreach()执行,它首先执行倒带()...

答案 1 :(得分:2)

在扩展IteratorIterator类以实现整个迭代器接口和/或创建迭代器的装饰器的同时,我也遇到过这种情况。

该装饰器已经是问题的解决方案,它只需要实现缺少的功能来消除不一致性。无需自动倒带:

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

示例:如果您的Iterator对象默认有效,例如ArrayIterator

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

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

这显示了IteratorIterator实现的不一致性,IteratorIterator对象未正确反映内部ArrayIterator的状态。使用IteratorDecorator可以治愈这个:

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

如果您已经跟进到此处,那么您可能需要考虑另一个特殊情况:如果您不需要使用内部迭代器rewind,则可以使用{{1}这也返回了有效性:

NoRewindIterator

将约翰内斯的“无自动倒回”参数考虑在内,这是有道理的,因为$noretit = new NoRewindIterator($it); var_dump($noretit->valid()); # bool(true) 期望迭代器不应该被重新整理并正确显示内部迭代器的有效性。

但正如NoRewindIterator所示,我不会进行任何类型的自动倒回以消除不一致。

答案 2 :(得分:0)

就像@johannes所说的那样,位置没有在IteratorIterator中初始化,因此在它运行任何其他方法或者与foreach()一起使用之前它是无效的

尝试

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

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

还要注意在unitiliazed IteratorIterator上:

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

请注意,您的代码段中的$arrayIter$iterIter->getInnerIterator()相同。

希望能有所启发。