クラスの名前のみ ( NoRewindIterator
)のように、マニュアルには具体的に次の文言があります。
NoRewindIterator - この反復子は巻き戻しできません。
具体的な方法については、次のとおりです。
NoRewindIterator::rewind() - 内側の反復子での巻き戻し操作を防ぎます。
これは、Iterator::rewind()
メソッドが内部反復子に渡されないことを意味します。テストもこれを示しています。これは私が実行した単純なものです(PHPの一部ではないすべてのイテレータのコードはIterator Gardenにあります):
$iterator = new RangeIterator(1, 1);
$debug = new DebugIteratorDecorator($iterator);
$noRewind = new NoRewindIterator($debug);
echo "first foreach:\n";
foreach ($noRewind as $value) {
echo "iteration value: $value\n";
}
このコードでは、debug-iterator が反復情報をオンザフライで出力 (エコー) します。
first foreach:
Iterating (RangeIterator): #0 valid()
Iterating (RangeIterator): #0 parent::valid() is TRUE
Iterating (RangeIterator): #0 current()
Iterating (RangeIterator): #0 parent::current() is 1
iteration value: 1
Iterating (RangeIterator): #1 next()
Iterating (RangeIterator): #1 after parent::next()
Iterating (RangeIterator): #1 valid()
Iterating (RangeIterator): #1 parent::valid() is FALSE
これが示すように、$iterator->rewind()
は呼び出されません。
これは、関連する質問で与えられたのと同じ理由からも理にかなっています: Why must I rewind IteratorIterator . は親クラスNoRewindIterator
から拡張され、親クラスIteratorIterator
とは異なりgetInnerIterator()
、メソッドは ではIterator
なく を返しますTraversable
。
この変更により、次の必要がある場合に巻き戻しを初期化できます。
echo "\n\$calling noRewind->getInnerIterator()->rewind():\n";
$noRewind->getInnerIterator()->rewind();
echo "\nsecond foreach:\n";
foreach ($noRewind as $value) {
echo "iteration value: $value\n";
}
デバッグ出力の例:
$calling noRewind->getInnerIterator()->rewind():
Iterating (RangeIterator): #0 rewind()
Iterating (RangeIterator): #0 after parent::rewind()
second foreach:
Iterating (RangeIterator): #0 valid()
Iterating (RangeIterator): #0 parent::valid() is TRUE
Iterating (RangeIterator): #0 current()
Iterating (RangeIterator): #0 parent::current() is 1
iteration value: 1
Iterating (RangeIterator): #1 next()
Iterating (RangeIterator): #1 after parent::next()
Iterating (RangeIterator): #1 valid()
Iterating (RangeIterator): #1 parent::valid() is FALSE
これらの詳細を知っていればOneTimeRewindIterator
、たとえば次のようなものを作成できます。
/**
* Class OneTimeRewindIterator
*/
class OneTimeRewindIterator extends NoRewindIterator
{
private $didRewind = FALSE;
public function rewind() {
if ($this->didRewind) return;
$this->didRewind = TRUE;
$this->getInnerIterator()->rewind();
}
}