вещь, которую вы хотите перебираем должны реализовать Traversable
. Однако вы не можете реализовать Traversable
напрямую; вам нужно реализовать один из его подтипов. Как вы будете делать все зависит от того, как будет использоваться объект.
Если вы хотите, вы можете просто реализовать Iterator
. Это работает достаточно хорошо, если ваш тип предназначен только для пересылки только вперед. Если вы решили построить итератор, вы будете иметь 5 методов для реализации:
current
, который извлекает значение в текущем местоположении;
key
, который извлекает ключ текущего местоположения;
next
, который переходит в следующее место;
rewind
, который сбрасывает текущее местоположение до первого; и
valid
, который возвращает false
, если итерация упала с конца перечня переименованного материала.
PHP называет эти методы в ходе итерации. В частности, предположим, что у вас есть такой код:
foreach ($it as $key => $value) {
doStuffWith($key, $value);
}
Это довольно эквивалентно следующему:
for ($it->rewind(); $it->valid(); $it->next()) {
$value = $it->current();
$key = $it->key(); // only if the foreach has a `$key =>`
doStuffWith($key, $value);
}
В основном вам просто нужно построить тип, который implements Iterator
и правильно реагирует на тех методах, вызываемых примерно в таком порядке. В идеале также должно быть возможно, что что-то произойдет между ними ... но это обычно не проблема, если вы не пропустите ссылки вокруг.
Если вам не нужна индивидуальная итерация, вместо этого вы можете просто реализовать IteratorAggregate
и вернуть существующий тип итератора, если он способен делать то, что вам нужно.(Например, если вы хотите разрешить цикл по внутреннему массиву, то для работы уже есть ArrayIterator
. Не нужно сворачивать самостоятельно.) Для IteratorAggregate
вам нужно только реализовать getIterator
, который возвращает что-то, что можно пропустить. Это лучшее решение, если у вас есть что-то, что уже может пройти один из built-in SPL iterators, или его можно легко свести к массиву или к чему-то еще.
то же цикл выше, при вызове на IteratorAggregate, будет приравнять к чему-то вроде
foreach ($it->getIterator() as $key => $value) {
doStuffWith($key, $value);
}
getIterator()
должен возвращать либо реализацию Iterator
или некоторую примитивную проходимую штучку, как массив.
Что касается итераторов в стиле Java, вы можете создать подтип Iterator, который может запомнить его место и петлю над вашей коллекцией, а затем реализовать в вашей коллекции IteratorAggregate
, чтобы вернуть экземпляр типа итератора.
Спасибо Майкл за этот хорошо отмеченный пример !!!! Я согласен с выходом! : P Cheers – user1216849