Pourquoi dois-je revenir en arrière IteratorIterator
Question
$arrayIter = new ArrayIterator( array(1, 2) );
$iterIter = new IteratorIterator($arrayIter);
var_dump($iterIter->valid()); //false
var_dump($arrayIter->valid()); //true
Si je premier appel $ iterIter-> rewind () , puis $ iterIter-> valide () est vrai. Je suis curieux de savoir pourquoi il faut que rewind () soit appelé. J'imagine qu'il ya de bonnes raisons pour cela, mais je me serais attendu à commencer simplement itération quel que soit l'état, il est iterator intérieur est, et le laisser en option pour revenir en arrière avant de commencer l'itération.
appelant à côté () semble aussi mettre dans un état « valide » (bien qu'il avance à la position suivante, ce qui suggère qu'il était auparavant à la première position).
$arrayIter = new ArrayIterator(array(1,2));
$iterIter = new IteratorIterator($arrayIter);
$iterIter->next();
var_dump($iterIter->valid());
Encore une fois, je suis curieux de savoir pourquoi je dois appeler rewind (), en dépit de l'itérateur interne étant dans un état valide.
La solution
Avec une nouvelle iterator position n'est pas initialisé, simplement pour des raisons de performances, vous pouvez empiler itérateurs sur d'autres itérateurs, si tous seraient un retour rapide pendant la construction il y aurait un certain impact sur les performances, en plus des itérateurs pourraient changer première valeur après que le constructeur a été exécuté -. qui est inconnu itérateurs plus loin
itérateurs sont généralement exécutés par foreach () qui fait un retour rapide () d'abord ...
Autres conseils
Alors que l'extension de la classe IteratorIterator
pour épargner la mise en œuvre toute interface iterator et / ou de créer un décorateur d'un itérateur Je cours dans ce aussi bien.
Ce décorateur est déjà la solution au problème, il n'a besoin que de mettre en œuvre les fonctionnalités manquantes pour supprimer l'incohérence. Pas besoin d'un rembobinage automatique:
class IteratorDecorator extends IteratorIterator
{
public function valid()
{
return $this->getInnerIterator()->valid();
}
}
Exemple: Si vous avez un objet Iterator
valide par défaut, par exemple ArrayIterator
:
$it = new ArrayIterator(array(1));
var_dump($it->valid()); # bool(true)
$itit = new IteratorIterator($it);
var_dump($itit->valid()); # bool(false)
Cela montre l'incohérence de la mise en œuvre de IteratorIterator
bien, l'objet IteratorIterator
ne reflète pas l'état du ArrayIterator
intérieur. En utilisant le IteratorDecorator
peut guérir ceci:
$decor = new IteratorDecorator($it);
var_dump($decor->valid()); # bool(true)
Et si vous avez suivi jusqu'à ici, voici un autre cas particulier, vous voudrez peut-être envisager: Si vous n'avez pas besoin d'avoir rewind
avec l'itérateur interne, vous pouvez simplement utiliser la NoRewindIterator
qui retourne la validité correcte ainsi :
$noretit = new NoRewindIterator($it);
var_dump($noretit->valid()); # bool(true)
Taken Johannes « pas auto-rewind » arguments en compte, cela fait sens, comme le NoRewindIterator
attend à ce que l'itérateur ne doit pas être rembobinées et montre correctement la validité de l'itérateur interne.
Mais comme le montre IteratorDecorator
, je ne fais aucune sorte de rembobinage automatique et de supprimer l'incohérence.
Comme @johannes a dit, la position n'a pas été initialisé dans le IteratorIterator
et il est donc pas valable avant tout autre de celui-ci pour des méthodes sont exécutées sur le ou il est utilisé avec foreach ()
Essayez de faire
var_dump( $iterIter->current() ); // NULL
var_dump( $iterIter->getInnerIterator()->current() ); // 1
Et
$iterIter->rewind();
var_dump( $iterIter->current() ); // 1
var_dump( $iterIter->getInnerIterator()->->current() ); // 1
Et notez aussi que sur une IteratorIterator unitiliazed:
$iterIter->next(); // 2
var_dump( $iterIter->current()) ; // 2 (from NULL to 2)
var_dump( $iterIter->getInnerIterator()->current() ); // 2
Notez que $arrayIter
de votre extrait de code est identique à $iterIter->getInnerIterator()
.
L'espoir que faire la lumière.