Pergunta

$arrayIter = new ArrayIterator( array(1, 2) );
$iterIter = new IteratorIterator($arrayIter);

var_dump($iterIter->valid()); //false
var_dump($arrayIter->valid()); //true

Se eu ligar primeiro $ iteriter-> rewind (), então $ iteriter-> válido () é verdade. Estou curioso para saber por que exige que Rewind () seja chamado. Eu imagino que há boas razões para isso, mas eu esperaria que simplesmente iniciasse a iteração em qualquer estado que seja o iterador interno e deixasse como uma opção retroceder antes de iniciar a iteração.

Chamando a seguir () também parece colocá -lo em um estado "válido" (embora avise a próxima posição, sugerindo que estava anteriormente na primeira posição).

$arrayIter = new ArrayIterator(array(1,2));
$iterIter = new IteratorIterator($arrayIter);

$iterIter->next();
var_dump($iterIter->valid()); 

Novamente, estou curioso para saber por que preciso chamar Rewind (), apesar do iterador interno estar em um estado válido.

Foi útil?

Solução

Com um novo iterador, a posição não é inicializada, simplesmente por motivo de desempenho, você pode empilhar iteradores em cima de outros iteradores, se todos eles rebobinarem durante a construção, haveria algum impacto no desempenho, além de alguns iteradores poderiam mudar seu primeiro valor após O construtor foi executado - o que é desconhecido para os iteradores mais distantes.

Os iteradores são geralmente executados por foreach () que faz um retrocesso () primeiro ...

Outras dicas

Enquanto estende o IteratorIterator Classe de sobra de implementação de toda a interface do iterador e/ou para criar um decorador de um iterador que eu também estive com isso.

Esse decorador já é a solução para o problema, ele só precisa implementar a funcionalidade ausente para remover a inconsistência. Não há necessidade de um auto-rego:

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

Exemplo: se você tem um Iterator objeto que é válido por padrão, por exemplo ArrayIterator:

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

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

Isso mostra a inconsistência do IteratorIterator implementação bem, o IteratorIterator o objeto não reflete adequadamente o interior ArrayIteratorEstado. Usando o IteratorDecorator pode curar isso:

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

E se você seguiu até aqui, aqui está outro caso especial que você pode querer considerar: se você não precisar rewind Com o iterador interno, você pode apenas usar o NoRewindIterator que retorna a validade correta também:

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

Levados em consideração a Johannes "nenhum argumento automático", isso faz sentido, pois o NoRewindIterator espera que o iterador não seja rewimado e mostre a validade do iterador interno corretamente.

Mas como o IteratorDecorator Mostra, eu também não faço nenhum tipo de auto-renda para remover a inconsistência.

Como @johannes disse, a posição não é inicializada no IteratorIterator e, portanto, não é válido antes que nenhum outro de seus métodos seja executado nele ou seja usado com foreach ()

Tente fazer

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

E também

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

E também observe que em um iteratorIterator unitário:

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

Observe que $arrayIter do seu snippet de código é idêntico a $iterIter->getInnerIterator().

Espero que esclareça um pouco de luz.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top