Perché devo tornare indietro IteratorIterator
Domanda
$arrayIter = new ArrayIterator( array(1, 2) );
$iterIter = new IteratorIterator($arrayIter);
var_dump($iterIter->valid()); //false
var_dump($arrayIter->valid()); //true
Se io prima chiamata $ iterIter-> rewind () , quindi $ iterIter-> valido () è vero. Sono curioso di sapere perchè si richiede che rewind () essere chiamato. Immagino che ci sia una buona ragione per questo, ma mi sarei aspettato di esso per avviare semplicemente l'iterazione in qualsiasi stato è iteratore interna è in, e lasciarlo come opzione per riavvolgere prima di iniziare iterazione.
chiamando next () sembra anche di metterlo in uno stato "valido" (anche se avanza alla posizione successiva, suggerendo che in precedenza era al primo posto).
$arrayIter = new ArrayIterator(array(1,2));
$iterIter = new IteratorIterator($arrayIter);
$iterIter->next();
var_dump($iterIter->valid());
Anche in questo caso, io sono curioso di sapere perchè ho bisogno di chiamare rewind (), nonostante l'iteratore interno essendo in uno stato valido.
Soluzione
Con un iteratore fresca la posizione non è inizializzato, semplicemente per ragioni di prestazioni, è possibile impilare iteratori in cima ad altre iteratori, se tutti loro sarebbe riavvolgere durante la costruzione ci sarebbe qualche impatto sulle prestazioni, in aggiunta alcuni iteratori potrebbero cambiare la loro primo valore dopo il costruttore è stato eseguito -. che è sconosciuto ai più lontano iteratori
Gli iteratori vengono di solito effettuate da foreach (), che fa un rewind () prima ...
Altri suggerimenti
Mentre si estende la classe IteratorIterator
di risparmiare attuare l'intera interfaccia iteratore e / o per creare un decoratore di un iteratore Ho corso in questo.
Questo decoratore è già la soluzione al problema, ha solo bisogno di implementare la funzionalità mancante per rimuovere l'inconsistenza. Non c'è bisogno di un auto-riavvolgimento:
class IteratorDecorator extends IteratorIterator
{
public function valid()
{
return $this->getInnerIterator()->valid();
}
}
Esempio: Se si dispone di un oggetto Iterator
che è valida per impostazione predefinita, ad esempio, ArrayIterator
:
$it = new ArrayIterator(array(1));
var_dump($it->valid()); # bool(true)
$itit = new IteratorIterator($it);
var_dump($itit->valid()); # bool(false)
Questo dimostra l'inconsistenza della realizzazione IteratorIterator
bene, l'oggetto IteratorIterator
non riflette correttamente lo stato del ArrayIterator
interiore. Utilizzando il IteratorDecorator
può guarire questo:
$decor = new IteratorDecorator($it);
var_dump($decor->valid()); # bool(true)
E se avete seguito fino a qui, qui è un altro caso particolare si potrebbe prendere in considerazione: se non c'è bisogno di avere rewind
con l'iteratore interno, si può semplicemente utilizzare il NoRewindIterator
che restituisce la validità corretta così :
$noretit = new NoRewindIterator($it);
var_dump($noretit->valid()); # bool(true)
Preso Johannes "no auto-rewind" argomenti in considerazione, questo ha un senso, come il NoRewindIterator
si aspetta che l'iteratore non dovrebbe essere riavvolto e mostra la validità del iteratore interno correttamente.
Ma come mostra IteratorDecorator
, non faccio nessun tipo di auto-riavvolgimento e per rimuovere l'inconsistenza.
Come @johannes detto, la posizione non è inizializzato nel IteratorIterator
e quindi non è valido prima di ogni altro di esso è metodi gestiscono su di esso o si utilizza con foreach ()
Prova a fare
var_dump( $iterIter->current() ); // NULL
var_dump( $iterIter->getInnerIterator()->current() ); // 1
E anche
$iterIter->rewind();
var_dump( $iterIter->current() ); // 1
var_dump( $iterIter->getInnerIterator()->->current() ); // 1
E anche notare che su un IteratorIterator unitiliazed:
$iterIter->next(); // 2
var_dump( $iterIter->current()) ; // 2 (from NULL to 2)
var_dump( $iterIter->getInnerIterator()->current() ); // 2
Si noti che $arrayIter
dal frammento di codice è identico a $iterIter->getInnerIterator()
.
La speranza che a far luce.