Почему я должен перематывать IteratorIterator - PullRequest
1 голос
/ 17 марта 2010
$arrayIter = new ArrayIterator( array(1, 2) );
$iterIter = new IteratorIterator($arrayIter);

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

Если я сначала вызову $ iterIter-> rewind () , то $ iterIter-> valid () будет истинным. Мне любопытно, почему это требует, чтобы rewind () был вызван. Я полагаю, что для этого есть веская причина, но я ожидал бы, что он просто начнет итерацию в любом состоянии, в котором находится его внутренний итератор, и оставит его в качестве опции для перемотки перед началом итерации.

вызов функции next () также, похоже, переводит его в «допустимое» состояние (хотя оно переходит на следующую позицию, предполагая, что ранее оно было на первой позиции).

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

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

Опять же, мне любопытно, почему мне нужно вызывать rewind (), несмотря на то, что внутренний итератор находится в допустимом состоянии.

Ответы [ 3 ]

5 голосов
/ 17 марта 2010

С новым итератором позиция не инициализируется, просто по соображениям производительности, вы можете размещать итераторы поверх других итераторов, если все они будут перематываться во время построения, это может оказать некоторое влияние на производительность, кроме того, некоторые итераторы могут изменить свои первое значение после выполнения конструктора, которое итераторам неизвестно далее.

Итераторы обычно выполняются функцией foreach (), которая сначала выполняет перемотку () ...

2 голосов
/ 28 февраля 2012

Расширяя класс IteratorIterator, чтобы сэкономить реализацию всего интерфейса итератора и / или создать декоратор итератора, с которым я тоже столкнулся.

Тот факт, что декоратор уже является решением проблемы, ему нужно только реализовать недостающие функциональные возможности для устранения несоответствия. Нет необходимости в автоперемотке:

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

Пример: если у вас есть объект Iterator, который является допустимым по умолчанию, например, ArrayIterator

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

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

Это хорошо показывает несоответствие реализации IteratorIterator, объект IteratorIterator неправильно отражает внутреннее состояние ArrayIterator. Использование IteratorDecorator может излечить это:

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

И если вы следили до этого момента, вот еще один особый случай, который вы могли бы рассмотреть: если вам не нужно иметь rewind с внутренним итератором, вы можете просто использовать NoRewindIterator, который возвращает срок действия также корректен:

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

Приняв во внимание аргументы Йоханнеса об отсутствии автоматической перемотки, это имеет смысл, так как NoRewindIterator ожидает, что итератор не должен быть перезаписан, и правильно показывает действительность внутреннего итератора.

Но, как показывает IteratorDecorator, я не делаю никакой автоматической перемотки, чтобы устранить несоответствие.

0 голосов
/ 17 марта 2010

Как сказал @johannes, позиция не инициализируется в IteratorIterator и, следовательно, она недопустима до того, как на ней запущены какие-либо другие ее методы или она используется с foreach ()

Попробуйте сделать

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

А также

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

А также обратите внимание, что на IteratorIterator с единичными ссылками:

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

Обратите внимание, что $arrayIter из вашего фрагмента кода идентично $iterIter->getInnerIterator().

Надеюсь, что пролил немного света.

...