php iterator spl

php - ¿Por qué debo rebobinar IteratorIterator?



spl (3)

Como dijo @johannes, la posición no se inicializa en el IteratorIterator y, por lo tanto, no es válida antes de que se ejecuten otros métodos o se usa con foreach ()

Intenta hacerlo

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

Y también

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

Y también tenga en cuenta que en un iterador IteradorIterador:

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

Tenga en cuenta que $arrayIter de su fragmento de código es idéntico a $iterIter->getInnerIterator() .

Espero que arroje algo de luz.

$arrayIter = new ArrayIterator( array(1, 2) ); $iterIter = new IteratorIterator($arrayIter); var_dump($iterIter->valid()); //false var_dump($arrayIter->valid()); //true

Si primero llamo $ iterIter-> rewind () , entonces $ iterIter-> valid () es verdadero. Tengo curiosidad por saber por qué se requiere que se rebobine (). Imagino que hay buenas razones para ello, pero esperaba que simplemente comenzara la iteración en cualquier estado en que esté el iterador interno, y lo dejo como una opción para rebobinar antes de comenzar la iteración.

llamar a next () también parece ponerlo en un estado "válido" (aunque avanza a la posición siguiente, sugiriendo que estaba previamente en la primera posición).

$arrayIter = new ArrayIterator(array(1,2)); $iterIter = new IteratorIterator($arrayIter); $iterIter->next(); var_dump($iterIter->valid());

De nuevo, tengo curiosidad de por qué necesito llamar a rewind (), a pesar de que el iterador interno está en un estado válido.


Con un iterador nuevo, la posición no se inicializa, simplemente por razones de rendimiento, puede apilar iteradores encima de otros iteradores, si todos se rebobinan durante la construcción, habría algún impacto en el rendimiento, además algunos iteradores podrían cambiar su primer valor después el constructor se ejecutó, lo cual es desconocido para los iteradores que están más lejos.

Iteradores usualmente son ejecutados por foreach () que hace un rebobinado () primero ...


Al extender la clase IteratorIterator para no aplicar toda la interfaz del iterador y / o crear un decorador de un iterador, me he estado encontrando con esto también.

Ese decorador ya es la solución al problema, solo necesita implementar la funcionalidad faltante para eliminar la inconsistencia. No es necesario un rebobinado automático:

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

Ejemplo: si tiene un objeto Iterator que es válido por defecto, por ejemplo, ArrayIterator :

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

Esto muestra la inconsistencia de la implementación IteratorIterator , el objeto ArrayIterator no refleja correctamente el estado interno del ArrayIterator . El uso de IteratorDecorator puede sanar esto:

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

Y si ha seguido hasta aquí, aquí hay otro caso especial que podría considerar: si no necesita haber rewind con el iterador interno, puede usar el NoRewindIterator que también devuelve la validez correcta:

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

Tomando en cuenta los argumentos de Johannes "sin rebobinado automático", esto tiene sentido, ya que el NoRewindIterator espera que el iterador no se rebobine y muestre la validez del iterador interno correctamente.

Pero como IteratorDecorator muestra, no realizo ningún tipo de rebobinado automático para eliminar la incoherencia.