Исключить элементы в итераторе

#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() функцию not rewind() … но это только у меня.

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]);
    }
}