$arrayIter = new ArrayIterator( array(1, 2) ); $iterIter = new IteratorIterator($arrayIter); var_dump($iterIter->valid()); //false var_dump($arrayIter->valid()); //true
Если я сначала вызову $ iterIter-> rewind () , то $ iterIter-> valid () будет true. Мне любопытно, почему это требует вызова перемотки (). Я предполагаю, что для этого есть веская причина, но я ожидал, что он просто начнет итерацию в любом состоянии, в котором находится внутренний итератор, и оставит его как возможность перемотать перед началом итерации.
вызов next () также, кажется, помещает его в «действительное» состояние (хотя он переходит к следующей позиции, предполагая, что он был ранее на первой позиции).
$arrayIter = new ArrayIterator(array(1,2)); $iterIter = new IteratorIterator($arrayIter); $iterIter->next(); var_dump($iterIter->valid());
Опять же, мне любопытно, почему мне нужно вызвать rewind (), несмотря на то, что внутренний итератор находится в правильном состоянии.
С новым итератором позиция не инициализируется, просто по соображениям производительности, вы можете складывать итераторы поверх других итераторов, если все они будут перематываться во время построения, будет некоторое влияние на производительность, кроме того, некоторые итераторы могут изменить свое первое значение после конструктор был выполнен – что еще не известно итераторам.
Итераторы обычно выполняются foreach (), который сначала выполняет перемотку () …
Расширяя класс 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
, я не делаю никакой автоматической перемотки, а также для устранения несогласованности.
Как и @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
А также обратите внимание, что на унифицированном Итераторе Итераторе:
$iterIter->next(); // 2 var_dump( $iterIter->current()) ; // 2 (from NULL to 2) var_dump( $iterIter->getInnerIterator()->current() ); // 2
Обратите внимание, что $arrayIter
из вашего фрагмента кода идентичен $iterIter->getInnerIterator()
.
Надеюсь, что пролить свет.