HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Теги: php, алгоритмы, программирование на php, древо, древовидная иерархия, рекурсивный метод, рекурсия в php</p>
1 <p>Теги: php, алгоритмы, программирование на php, древо, древовидная иерархия, рекурсивный метод, рекурсия в php</p>
2 <p>Однажды я обнаружил очень интересную особенность развития современных web-программистов. Мы смело оперируем фабриками, синглтонами и декораторами, но забываем о такой фундаментальной части программирования, как<strong>классические алгоритмы</strong>.</p>
2 <p>Однажды я обнаружил очень интересную особенность развития современных web-программистов. Мы смело оперируем фабриками, синглтонами и декораторами, но забываем о такой фундаментальной части программирования, как<strong>классические алгоритмы</strong>.</p>
3 <p>Ведь если присмотреться к их реализации, то это тоже своего рода<strong>паттерны</strong>. С институтской скамьи можно вспомнить, к примеру,<strong>nested sets</strong>,<strong>b-tree</strong>,<strong>сортировку "пузырьком"</strong>. Реализация многих алгоритмов давно устоялась. А потому я хотел бы посвятить свою статью<strong>алгоритмам и их применении в PHP</strong>.</p>
3 <p>Ведь если присмотреться к их реализации, то это тоже своего рода<strong>паттерны</strong>. С институтской скамьи можно вспомнить, к примеру,<strong>nested sets</strong>,<strong>b-tree</strong>,<strong>сортировку "пузырьком"</strong>. Реализация многих алгоритмов давно устоялась. А потому я хотел бы посвятить свою статью<strong>алгоритмам и их применении в PHP</strong>.</p>
4 <p>Начну я с самого простого -<strong>построения древовидной иерархии</strong>.</p>
4 <p>Начну я с самого простого -<strong>построения древовидной иерархии</strong>.</p>
5 <p>Казалось бы, что тут сложного? В базе данных есть таблица примерно следующего содержания:</p>
5 <p>Казалось бы, что тут сложного? В базе данных есть таблица примерно следующего содержания:</p>
6 <p>Необходимо представить этот массив в виде древовидного меню. Я не буду говорить о том, какими неправильными способами можно решить эту задачу. Единственно верный подход в данном случае -<strong>рекурсивный метод</strong>.</p>
6 <p>Необходимо представить этот массив в виде древовидного меню. Я не буду говорить о том, какими неправильными способами можно решить эту задачу. Единственно верный подход в данном случае -<strong>рекурсивный метод</strong>.</p>
7 <p>Алгоритм (паттерн, если так хотите) будет примерно следующим: 0. Создаём объект дерева и выбираем все элементы в таблице. 1. Вызываем метод построения. Он инициализирует сборку массива родительских категорий. Именно этот момент является ноу-хау данного алгоритма. Он позволяет нам организовать изящную рекурсию. 2. Итеративно обходим массив, начиная с нулевого элемента. Выводим информацию о текущем элементе. 3. Увеличиваем уровень погружения. Рекурсивно вызываем метод для дочернего элемента. Если он есть в массиве родительских категорий, то идем к шагу 2, иначе - выходим в шаг-инициализатор. 4. Уменьшаем уровень погружения. Выходим из итерации.</p>
7 <p>Алгоритм (паттерн, если так хотите) будет примерно следующим: 0. Создаём объект дерева и выбираем все элементы в таблице. 1. Вызываем метод построения. Он инициализирует сборку массива родительских категорий. Именно этот момент является ноу-хау данного алгоритма. Он позволяет нам организовать изящную рекурсию. 2. Итеративно обходим массив, начиная с нулевого элемента. Выводим информацию о текущем элементе. 3. Увеличиваем уровень погружения. Рекурсивно вызываем метод для дочернего элемента. Если он есть в массиве родительских категорий, то идем к шагу 2, иначе - выходим в шаг-инициализатор. 4. Уменьшаем уровень погружения. Выходим из итерации.</p>
8 <p>Итак, метод сборки массива категорий будет выглядеть примерно вот так:</p>
8 <p>Итак, метод сборки массива категорий будет выглядеть примерно вот так:</p>
9 private function getCategoryArray() { $query = $this-&gt;db_connect-&gt;prepare("SELECT * FROM tree_table"); $query-&gt;execute(); $result = $query-&gt;fetchAll(PDO::FETCH_OBJ); $category_array = array(); foreach ($result as $value) { $category_array[$value-&gt;id_parent][] = $value; } return $category_array; }<p>Далее напишем наш рекурсивный метод в соответствии с приведенным выше алгоритмом:</p>
9 private function getCategoryArray() { $query = $this-&gt;db_connect-&gt;prepare("SELECT * FROM tree_table"); $query-&gt;execute(); $result = $query-&gt;fetchAll(PDO::FETCH_OBJ); $category_array = array(); foreach ($result as $value) { $category_array[$value-&gt;id_parent][] = $value; } return $category_array; }<p>Далее напишем наш рекурсивный метод в соответствии с приведенным выше алгоритмом:</p>
10 public function buildTree($parent_id, $tree_level) { if (isset($this-&gt;category[$parent_id])) { foreach ($this-&gt;category[$parent_id] as $value) { echo " " . $value-&gt;id_tree_test . " : " . $value-&gt;title . " "; $tree_level++; $this-&gt;buildTree($value-&gt;id_tree_test, $tree_level); $tree_level--; } } }<p>Теперь можем вызвать построение дерева, начиная с 0 элемента и 0 уровня. Замечу, что приведённый метод может вызывать построение с любой вложенной ноды и не ограничен по глубине.</p>
10 public function buildTree($parent_id, $tree_level) { if (isset($this-&gt;category[$parent_id])) { foreach ($this-&gt;category[$parent_id] as $value) { echo " " . $value-&gt;id_tree_test . " : " . $value-&gt;title . " "; $tree_level++; $this-&gt;buildTree($value-&gt;id_tree_test, $tree_level); $tree_level--; } } }<p>Теперь можем вызвать построение дерева, начиная с 0 элемента и 0 уровня. Замечу, что приведённый метод может вызывать построение с любой вложенной ноды и не ограничен по глубине.</p>
11 $tree = new Tree(); $tree-&gt;buildTree(0, 0);<p>А вот как будет<a>выглядеть наше дерево</a>в итоге:</p>
11 $tree = new Tree(); $tree-&gt;buildTree(0, 0);<p>А вот как будет<a>выглядеть наше дерево</a>в итоге:</p>
12 &lt;?php class Tree { private $db_connect = null; public $category = array(); public $tree = array(); public function __construct() { # $this-&gt;db_connect = new PDO("mysql:dbname=devenergru_drup1;host=localhost", "devenergru_drup1", "weduucixwa"); $this-&gt;category = $this-&gt;getCategoryArray(); } private function getCategoryArray() { $category_array = [ 0 =&gt; [ [ 'id_tree_test' =&gt; 2, 'id_parent' =&gt; 0, 'title' =&gt; "Два" ] ], 1 =&gt; [ [ 'id_tree_test' =&gt; 4, 'id_parent' =&gt; 1, 'title' =&gt; "Четыре" ] ], 2 =&gt; [ [ 'id_tree_test' =&gt; 1, 'id_parent' =&gt; 2, 'title' =&gt; "Один" ], [ 'id_tree_test' =&gt; 5, 'id_parent' =&gt; 2, 'title' =&gt; "Пять" ] ], 4 =&gt; [ [ 'id_tree_test' =&gt; 3, 'id_parent' =&gt; 4, 'title' =&gt; "Три" ] ] ]; return $category_array; } public function buildTree($parent_id, $level) { if (isset($this-&gt;category[$parent_id])) { foreach ($this-&gt;category[$parent_id] as $value) { echo "&lt;div style=\"margin-left:" . ($level * 25) . "px;\"&gt;" . $value["id_tree_test"] . " : " . $value["title"] . "&lt;/div&gt;"; $level++; $this-&gt;buildTree($value["id_tree_test"], $level); $level--; } } } } $tree = new Tree(); $tree-&gt;buildTree(0, 0); ?&gt;<p>Данный метод применим при построении меню на сайте, каталогов продукции и т. п. У него, разумеется, есть недостатки. При построении достаточно большого каталога метод будет работать довольно долго. Но выигрыш тут в том, что<strong>метод можно модифицировать</strong>и ограничить не только уровнем входа, но и уровнем погружения. Таким образом, можно достраивать дерево постепенно при запросе пользователей, что решит данную проблему.</p>
12 &lt;?php class Tree { private $db_connect = null; public $category = array(); public $tree = array(); public function __construct() { # $this-&gt;db_connect = new PDO("mysql:dbname=devenergru_drup1;host=localhost", "devenergru_drup1", "weduucixwa"); $this-&gt;category = $this-&gt;getCategoryArray(); } private function getCategoryArray() { $category_array = [ 0 =&gt; [ [ 'id_tree_test' =&gt; 2, 'id_parent' =&gt; 0, 'title' =&gt; "Два" ] ], 1 =&gt; [ [ 'id_tree_test' =&gt; 4, 'id_parent' =&gt; 1, 'title' =&gt; "Четыре" ] ], 2 =&gt; [ [ 'id_tree_test' =&gt; 1, 'id_parent' =&gt; 2, 'title' =&gt; "Один" ], [ 'id_tree_test' =&gt; 5, 'id_parent' =&gt; 2, 'title' =&gt; "Пять" ] ], 4 =&gt; [ [ 'id_tree_test' =&gt; 3, 'id_parent' =&gt; 4, 'title' =&gt; "Три" ] ] ]; return $category_array; } public function buildTree($parent_id, $level) { if (isset($this-&gt;category[$parent_id])) { foreach ($this-&gt;category[$parent_id] as $value) { echo "&lt;div style=\"margin-left:" . ($level * 25) . "px;\"&gt;" . $value["id_tree_test"] . " : " . $value["title"] . "&lt;/div&gt;"; $level++; $this-&gt;buildTree($value["id_tree_test"], $level); $level--; } } } } $tree = new Tree(); $tree-&gt;buildTree(0, 0); ?&gt;<p>Данный метод применим при построении меню на сайте, каталогов продукции и т. п. У него, разумеется, есть недостатки. При построении достаточно большого каталога метод будет работать довольно долго. Но выигрыш тут в том, что<strong>метод можно модифицировать</strong>и ограничить не только уровнем входа, но и уровнем погружения. Таким образом, можно достраивать дерево постепенно при запросе пользователей, что решит данную проблему.</p>
13 <p>Я не рассматриваю здесь проблемы хранения такой структуры, т. к. нас сейчас интересует только обход массива.</p>
13 <p>Я не рассматриваю здесь проблемы хранения такой структуры, т. к. нас сейчас интересует только обход массива.</p>
14 <p>На этом всё! Безошибочного вам кода!</p>
14 <p>На этом всё! Безошибочного вам кода!</p>
15  
15