Вопрос

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

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

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

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

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

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

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

А также обратите внимание, что в унифицированном IteratorIterator:

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

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

Надеюсь, это пролило некоторый свет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top