Структурная структура ООП по иерархии PHP

Каков наилучший способ представления структуры навигации дерева с помощью PHP? Мне нужно иметь возможность отслеживать текущее расположение страницы в дереве с помощью тропы для хлебных крошек. Части дерева генерируются из базы данных, например make -> models. Каждая модель имеет такую ​​же эквивалентную ветвь дерева, как:

Сделайте> Модель> (Площадь 1, Площадь 2, Площадь 3).

Части дерева могут меняться со временем. Лучше ли иметь иерархическую структуру статического класса или динамическое решение, в котором классы повторно используются?

Надеюсь, это объяснено просто.

    Я бы пошел с:

    • список $nodes для каждого элемента [если пустым является, конечно, листовой узел];
    • поле $parent для родительского элемента [если null это корневой узел].

    Таким образом, вы можете восстановить getTrail() для каждого узла, предоставив им метод getTrail() :

     public function getTrail() { $parent = $this -> parent(); $trail = array(); while($parent !== NULL) { // push parent element to trail $trail[] = $parent; // go backwards one node $parent = $parent -> parent(); } // you want trail in reverse order [from root to latest] return array_reverse($trail); } 

    Если ваши узлы отличаются по типу, будьте чисты, предоставляя интерфейс getTrail() с помощью getTrail() / getParent() .

     class TreeNode { /** * the parent node * * @var TreeNode */ private $parentNode=null; /** * the children of this node * * @var TreeNode[] */ private $children=array(); /** * The user element this tree node holds. * * @var Object */ private $element; } 

    С точки зрения OO я бы рекомендовал определить интерфейс, такой как:

     interface BreadcrumbInterface { public function getLabel(); public function getParent(); // returns an instance of BreadcrumbInterface, or null } 

    Затем вы создадите класс Page, который реализует этот интерфейс и может необязательно содержать «родительский», который также должен реализовать этот интерфейс. Это создаст вам иерархию.

    Отличный способ получить полные панировочные сухари (при чистке ваших шаблонов проектирования OO в процессе) – использовать шаблон посетителя . В этом случае вы, вероятно, хотите определить общий абстрактный класс, а также интерфейс, чтобы «абстрагировать» логику обработки посетителя …

     abstract class BaseNode implements BreadcrumbInterface { protected $parent = null; public function accept(BreadcrumbVisitor $visitor) { $visitor->visit($this); } public function setParent(BreadcrumbInterface $parent) { $this->parent = $parent; } public function getParent() { return $this->parent; } } class BreadcrumbVisitor { protected $breadcrumbs = array(); public function visit(BreadcrumbInterface $node) { $parent = $node->getParent(); if ($parent instanceof BaseNode) { $parent->accept($this); } $this->breadcrumbs[] = $node->getLabel(); } public function getBreadcrumbs() { return $this->breadcrumbs; } } , abstract class BaseNode implements BreadcrumbInterface { protected $parent = null; public function accept(BreadcrumbVisitor $visitor) { $visitor->visit($this); } public function setParent(BreadcrumbInterface $parent) { $this->parent = $parent; } public function getParent() { return $this->parent; } } class BreadcrumbVisitor { protected $breadcrumbs = array(); public function visit(BreadcrumbInterface $node) { $parent = $node->getParent(); if ($parent instanceof BaseNode) { $parent->accept($this); } $this->breadcrumbs[] = $node->getLabel(); } public function getBreadcrumbs() { return $this->breadcrumbs; } } 

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

    Редактировать:

    Добавление примерного примера использования:

     $rootPage = new Page(/*...*/); $parentPage = new Page(/*...*/); $parentPage->setParent($rootPage); // In reality you most likely wouldn't be building this structure so explicitly. Each object only needs to know about it's direct parent $currentPage = new Page(/*...*/); $currentPage->setParent($parentPage); $visitor = new BreadcrumbVisitor(); $currentPage->accept($visitor); $breadcrumbs = $visitor->getBreadcrumbs(); // returns an array, where the first element is the root // then you can implode with ' > ' if you want $breadcumbString = implode(' > ', $breadcrumbs);