Нужен совет по итератору для обхода дерева

Привет, мне нужен совет по итератору.

У меня есть объект категории, который может содержать коллекцию элементов, а также может иметь дочерние категории.

Из доктрины ORM я получаю набор объектов категорий. Теперь я хочу пройтись по этой коллекции и сгладить структуру дерева категорий. Таким образом, дочерние категории находятся на том же уровне, что и родительские. Я также хотел бы отфильтровать детей.

Может быть, кто-нибудь может указать мне правильное направление, в настоящее время немного потерянное в облаке Iterator.

<?php

class Category
{
    private $name;

    private $children;

    private $type;

    private $parent;

    private $items;

    //parent category
    public function getParent()
    {
        return $this->parent;
    }

    public function setItems($items)
    {
        $this->items = $items;
    }


    public function getItems()
    {
        return $this->items;
    }

    //colelction of categories
    public function getChildren()
    {
        return $this->children;
    }
}

person Fino    schedule 08.06.2012    source источник
comment
похоже на вопрос кодека   -  person Steve    schedule 09.06.2012
comment
Нет, я прошу совета, так дайте мне совет, в основном, какой итератор выбрать...   -  person Fino    schedule 09.06.2012


Ответы (2)


Вам просто нужно реализовать интерфейс RecursiveIterator. Затем вы можете перебрать его, используя конкретный RecursiveIteratorIterator.

Чтобы помочь вам понять...

RecursiveIterator сам по себе не очень, гм, "рекурсивный". Это просто то, что предлагает определенные методы, которые можно использовать для получения дочерних элементов (подзадачу рекурсии можно рассматривать как «дочерние элементы»). Обратите внимание, что RecursiveIterator.getChildren() должен возвращать своих дочерних элементов в виде другого RecursiveIterator.

Вы можете вручную выполнить итерацию простого RecursiveIterator, но было бы довольно сложно отслеживать все подитераторы, возвращаемые рекурсивными вызовами getChildren, и поддерживать правильную глубину и т. д... вот где появляется RecursiveIteratorIterator...

RecursiveIteratorIterator — это то, что выполняет фактическую работу по систематическому обходу структуры, имитируя рекурсию. Он выполняет итерацию по RecursiveIterator, как если бы это был плоский список, но для каждого элемента в списке он проверяет текущий элемент на наличие дочерних элементов. Если это hasChildren, он вызывает getChildren и сохраняет ссылку на этот новый дочерний итератор в стеке. Он управляет стеком таким образом, который обеспечивает ожидаемое вами рекурсивное поведение (во многом так же, как вы вручную преобразуете рекурсивную функцию в итеративную версию).

Чтобы было ясно, вы не кодируете свой собственный RecursiveIteratorIterator, а просто создаете конкретную реализацию php. Этот класс существует исключительно для того, чтобы скрыть сложности и управлять всеми многочисленными объектами RecursiveIterator, которые создаются в процессе обхода от вас, и представлять вам результат обхода в виде того, что кажется плоским списком. RecursiveIteratorIterator — очень сложный внутри класс.

Что касается фильтрации-

Есть несколько способов. Для простоты использования я рекомендую использовать CallbackFilterIterator, если у вас php 5.4 . В противном случае вы должны расширить FilterIterator.

Однако оба они отфильтровывают элементы после того, как представление рекурсивной структуры было сведено к структуре, подобной списку. Таким образом, ваш фильтр не может, например, сказать «пропустить все это поддерево», он может сказать только «пропустить этот отдельный элемент». Если вам нужно сказать «пропустить все это поддерево», вам нужно использовать RecursiveCallbackFilterIterator или расширить RecursiveFilterIterator, если у вас нет php 5.4

вы, вероятно, хотите начать с

class RecursiveCategoryIterator implements RecursiveIterator {...

И это должно содержать список объектов категории.

person goat    schedule 08.06.2012

Вы должны начать с корневого узла и рекурсивно пройти каждый $this->getChildren() (узлов и подузлов ( и их подузлы (и их подузлы (и их подузлы)))) (рекурсия), пока не будет null. Это приведет к чему-то вроде этого:

(Start)
Root node
-> 1st Child node
--> Grandchild node
-> 2nd Child node
-> 3rd Child node
-> 4th Child node
--> Grandhild node
(No more children so exit)
person tango whiskey double    schedule 08.06.2012
comment
Любые предложения, какой (PHP) итератор выбрать для этого? - person Fino; 09.06.2012
comment
Создайте свой собственный, используя implements Iterator php.net/manual/en/class.iterator.php - person tango whiskey double; 09.06.2012