質問には逆の順序で答えます。
foreach
rewind
それらの違いforeach
とwhile
イテレータを使用する場合の違いを呼び出す必要なしに完全に機能します
foreach
内部でへの呼び出しをrewind()
行うので、自分で呼び出す必要はありません。これは常に行われるため、すでにイテレータを使用している場合でも、foreach
ループは最初からやり直します。(これは、でラップすることで回避できますNoRewindIterator
)。
配列が開始または呼び出されたことはありません。whileループに$iterator->rewind()が必要な理由
SPLイテレータはforeach
、この場合、メソッド呼び出しの重複を回避するために使用されるように設計されています。RecursiveIteratorIterator
が構築時にメソッドを呼び出す場合、ループの開始RecursiveArrayIterator::rewind()
時に再度呼び出されます。foreach
そのため、呼び出しは行われません。
なぜ余分なAがCではないのですか?
これを理解するには、RecursiveArrayIterator
実際に呼び出されるメソッドを確認するのが便利です。
<?php
class DebugRAI extends RecursiveArrayIterator {
public function rewind() { echo __METHOD__, "\n"; return parent::rewind(); }
public function current() { echo __METHOD__, "\n"; return parent::current(); }
public function key() { echo __METHOD__, "\n"; return parent::key(); }
public function valid() { echo __METHOD__, "\n"; return parent::valid(); }
public function next() { echo __METHOD__, "\n"; return parent::next(); }
}
$array = array("A", "B", "C");
$iterator = new RecursiveIteratorIterator(new DebugRAI($array));
while ($iterator->valid()) {
echo $iterator->current(), "\n";
$iterator->next();
}
これにより、次の出力が生成されます。
DebugRAI::valid
DebugRAI::current
A
DebugRAI::valid
DebugRAI::valid
A
DebugRAI::next
DebugRAI::valid
DebugRAI::valid
DebugRAI::current
B
DebugRAI::next
DebugRAI::valid
DebugRAI::valid
DebugRAI::current
C
DebugRAI::next
DebugRAI::valid
DebugRAI::valid
出力は少し奇妙に見えます。特に、2回目の反復ではnext()
呼び出しが欠落しているため、同じ要素にとどまります。
この理由は、RecursiveIteratorIterator
実装の特殊性です。イテレータは状態で開始し、このRS_START
状態での最初のnext
呼び出しはチェックするだけhasChildren()
で、実際には基になるイテレータのnext()
メソッドを呼び出しません。これが行われた後、それは呼び出しが適切に行われるRS_NEXT
モードに切り替わります。next()
そのため、前進が1ステップ遅れます。
私の目にはこれはバグですが、https://bugs.php.net/bug.php?id=44063はそうではないと主張しています。