#php #iteration
#php #итерация
Вопрос:
Я ищу наилучшую практику в интерфейсе итератора PHP.
Представьте, что у меня есть меню с разными пунктами. Для каждого из элементов я могу включать или выключать видимость. Вы знаете подходящее место для размещения этого фильтра? Я думал о методе Iterator::rewind() для выполнения отдельного цикла, но мне не нравится сам факт повторного перебора элементов.
Мне кажется, я вижу дерево для деревьев. Надеюсь, вы сможете помочь.
Ответ №1:
Эмм, ты не можешь просто использовать continue
?
$exclude=array(0,2,3,5);
$data=array('Item1','Item2','Item3','Item4','Item5','Item6');
foreach($data as $id=>$value){
if(in_array($id,$exclude))continue;
echo $value.' ';
}
Учитывая, что у вас есть свойство видимости, вы бы сделали что-то вроде if(!visible)continue;
Комментарии:
1. Конечно, я могу. Но именно поэтому ООП так полезен — поместить все на свои места и быть СУХИМ . В любом случае — спасибо за это!
2. Если вы действительно хотите это сделать, я бы посоветовал использовать
next()
функцию notrewind()
… но это только у меня.3. Вопрос заключается в фильтрации определенных элементов в зависимости от свойства элемента, а не по списку идентификаторов. Это возможно и с
foreach
, но ваше решение проще таким образом:$toDisplay = array_diff(array_keys($data), $exclude)
;
Ответ №2:
Взгляните на класс abstrakt FilterIterator. Будет выглядеть примерно так
class MyFilterIterator extends FilterIterator {
public function accept () {
$current = $this->current();
// Test, if it is valid
return $boolean;
}
}
$iterator = new MyFilterIterator($myInnerIterator);
Таким образом, вы также отделяете меню от фильтра, что упрощает замену фильтра, если вы хотите его изменить.
Комментарии:
1. Я уже использую отдельный итератор. Я немного смущен необходимостью второго итератора, повторяющего исходный MenuIterator. В любом случае — это отлично работает!
2. Если вы посмотрите на файловые итераторы (особенно если вы хотите выполнять итерации по ним рекурсивно), может случиться так, что вам понадобится 4 или 5 итераторов, сложенных вместе : D Конечно, вам это не нужно (в значении этого слова), вы также можете объединить все в один, но это будет чище, если у каждого класса есть своя специфическая работа и он не выполняет слишком много («разделение задач»).
3. Да, ваша запись. Я думал об этом некоторое время и пришел к простому решению, что MenuIterator расширяет FilterIterator. Таким образом, я могу использовать ArrayIterator, созданный с помощью пунктов меню, чтобы передать его конструктору FilterIterator. Как вы сказали, я также разделяю процесс итерации на MenuIterator и дополнительный RecursiveTreeIterator … Итератор, итератор, итератор … тьфу. Это отлично работает! Еще раз спасибо!
Ответ №3:
Эта реализация итератора будет сканировать только видимые элементы. Вы можете настроить класс, чтобы параметризовать фильтр.
class myItem implements Iterator {
private $position = -1;
public function __construct() {
$this->position = -1; // mean unknown position
}
function rewind() {
$this->position = -1;
$this->next();
}
function current() {
return $this->array[$this->position];
}
function key() {
return $this->position;
}
function next() {
$p = $this->position 1;
// skip invisible items
while ( isset($this->array[$p]) amp;amp; (!$this->array[$p]->visible)) $p ;
$this->position = $p;
}
function valid() {
return isset($this->array[$this->position]);
}
}