Построение дерева иерархии с помощью PHP / MySQL

Рассмотрим пример построения дерева иерархии (в развернутом виде) на основе информации из базы данных с помощью PHP и MySQL. Ключ к решению данной задачи — использование рекурсивной функции. Иерархия разделов будет храниться в таблице базы данных MySQL.

Ниже на скриншоте показана данная таблица (catalogue):

  • id — первичный ключ таблицы
  • pid — id родительского раздела

Далее напишем следующий PHP-скрипт:

1. Файл dbopen.php (открывает соединение с MySQL)

<?php
 $hostName = "";
 $userName = "yura";
 $password = "yura";
 $databaseName = "tree";
 if (!($link=mysql_connect($hostName,$userName,$password))) {
 printf("Ошибка при соединении с MySQL !n");
 exit();
 }
 if (!mysql_select_db($databaseName, $link)) {
 printf("Ошибка базы данных !");
 exit();
 } 
?>

2. Файл index.php (основной скрипт)

<?php 
include( "dbopen.php" ); 

function ShowTree($ParentID, $lvl) { 

global $link; 
global $lvl; 
$lvl++; 

$sSQL="SELECT id,title,pid FROM catalogue WHERE pid=".$ParentID." ORDER BY title";
$result=mysql_query($sSQL, $link);

if (mysql_num_rows($result) > 0) {
echo("<UL>n");
while ( $row = mysql_fetch_array($result) ) {
$ID1 = $row["id"];
echo("<LI>n");
echo("<A HREF=""."?ID=".$ID1."">".$row["title"]."</A>"." n");
ShowTree($ID1, $lvl); 
$lvl--;
}
echo("</UL>n");
}

}

ShowTree(0, 0); 

mysql_close($link); 

?>

Всю работу выполняет рекурсивная функция ShowTree(). Ниже на скриншоте показан пример работы index.php:

телеграм канал. Подпишись, будет полезно!

Комментарии (7)

Гриорий 2011-09-28 07:50:44
P.s я писал на js. не сильно отличается. Спасибо за идею!

function PrintShopCatList(){
var s_cat_m_l=$('.shop_category_menu_list');
s_cat_m_l.html('');
str="<ul>n";
ShowTree(0);
str+="</ul>n";
s_cat_m_l.append(str);
}

var str='';
function ShowTree(ParentID) {
var result=SCatList.GetChild(ParentID, false);

if (result.length > 0) {
for (var i=0; i<result.length; i++){
str+="<li>";
var ID1=SCatList[result[i]].id;
str+="#";
if(SCatList.GetChild(ID1,false).length>0){
str+="<ul>n";
ShowTree(ID1);
str+="</ul>n";
}else{
str+="</li>n";
}
}
}
}
Гриорий 2011-09-28 07:50:27
Я просто в бешенстве от простоты автора!
Зачем ему $link если он нигде не используется!

Где закрывающийся тэг </li> ???

И при всем уважении такого результата при этом коде получиться не может, там в исходнике html не пойми что будет!!
Fivell 2010-12-23 16:15:22
Лучше использовать references . Можно все сделать 1 запросом и без рекурсии
вот пример - http://phpblog.com.ua/2010/06/tree-with-references/
Spider 2010-12-15 09:54:33
Есть ещё один способ, но требующий умного подхода. Выбрать всё из базы одним запросом и запихать в многоуровневый массив, и уже потом работать с массивом. Загвоздка состоит в том, что бы отсортировать массив так, что бы сабы были именно под своими парентами.
К примеру есть такой массив:

Array (
[0] => Array (
[s_id] => 5
[s_title] => Контент сайта
[c_id] => 34
[c_parent] => 0
[c_title] => Контент сайта
)
[1] => Array (
[s_id] => 6
[s_title] => Статьи
[c_id] => 35
[c_parent] => 0
[c_title] => Web дизайн
)
[2] => Array (
[s_id] => 6
[s_title] => Статьи
[c_id] => 36
[c_parent] => 40
[c_title] => Web программирование
)
[3] => Array (
[s_id] => 6
[s_title] => Статьи
[c_id] => 37
[c_parent] => 36
[c_title] => PHP
)
[4] => Array (
[s_id] => 6
[s_title] => Статьи
[c_id] => 38
[c_parent] => 0
[c_title] => JavaScript
)
[5] => Array (
[s_id] => 6
[s_title] => Статьи
[c_id] => 39
[c_parent] => 0
[c_title] => MySQL
)
[6] => Array (
[s_id] => 6
[s_title] => Статьи
[c_id] => 40
[c_parent] => 0
[c_title] => Joomla
)
)

Описание:
[s_id] - ид секции
[s_title] => заголовок секции
[c_id] => ид категории
[c_parent] => родитель категории
[c_title] => заголовок категории
Это полная выборка из бд. Сделать что бы было так

Контент сайта
--Контент сайта

Статьи
--Web дизайн
--JavaScript
--MySQL
--Joomla
----Web программирование
------PHP
пока никто не смог, а было бы хорошо
Виталий 2010-11-27 23:10:33
@bibendi:
Этот метод стоит использовать, если у вас максимальный размер вложенности состовляет не более 3-4 уровней.

Если же больше, то тут тоже надо смотреть, а как сильно будет нагружатся БД??
Т.е. на сколько часто будет извлекатсья информация, допусти для популярного интернет-магазина с подкатегориями более чем в 2-3 уровня это будет непозволительная роскошь использовать столько ресурсов.

Короче, к чему я всё клоню, есть такой алгоритм Nested Sets (вложенные множества).
Вот его и нужно использовать, если предпологается большая многоуровневая вложенность и/или большая нагрузка на сервер - читай много посетителей.

Конечно, кто-то скажет, что эта бодяга решается с помошью кэширования, безусловно его можно использовать и даже нужно, но в совокупности с этим алгоритмом вы добъётесь впечатляющих результатов скорости, т.к. для извлечения пркатически любой информации из дерева необходимо всего ОДИН запрос в БД.

здесь есть инфа, если кого заинтересовало http://www.getinfo.ru/article610.html
не сочтите за рекламу другого сайта.

Я просто столкнулся с такой проблемой, когда закачик дал задание разработать каталог с 6-8 уровнями вложенности и в каталоге было более 1500 категорий о_О
Уважаемый, для этого и существует кеширование файлов.
Один раз подключились, загнали все у виде массива в файл, а потом просто вытаскиваеш. Когда нужно будет, так и обновиш файл.
Если что, смотри в сторону serialize()
Silius 2009-12-06 12:23:46
Так и понял зачем выводить целый новый файл для подключения к базе (bdopen.php).
Намного проще сделать:

<?
$hostName = "";
$userName = "yura";
$password = "yura";
$databaseName = "tree";

$link=mysql_connect($hostName,$userName,$password) or
die ("Ошибка при соединении с MySQL !n");

$db=mysql_select_db($databaseName, $link) or
die ("Ошибка базы данных !");

#Ну а сюдой вставить код из файла (tree.php)

?>
Зачем нужны if - ы?
bibendi 2008-05-11 08:43:41
Этот метод стоит использовать, если у вас максимальный размер вложенности состовляет не более 3-4 уровней.

Если же больше, то тут тоже надо смотреть, а как сильно будет нагружатся БД??
Т.е. на сколько часто будет извлекатсья информация, допусти для популярного интернет-магазина с подкатегориями более чем в 2-3 уровня это будет непозволительная роскошь использовать столько ресурсов.

Короче, к чему я всё клоню, есть такой алгоритм Nested Sets (вложенные множества).
Вот его и нужно использовать, если предпологается большая многоуровневая вложенность и/или большая нагрузка на сервер - читай много посетителей.

Конечно, кто-то скажет, что эта бодяга решается с помошью кэширования, безусловно его можно использовать и даже нужно, но в совокупности с этим алгоритмом вы добъётесь впечатляющих результатов скорости, т.к. для извлечения пркатически любой информации из дерева необходимо всего ОДИН запрос в БД.

здесь есть инфа, если кого заинтересовало http://www.getinfo.ru/article610.html
не сочтите за рекламу другого сайта.

Я просто столкнулся с такой проблемой, когда закачик дал задание разработать каталог с 6-8 уровнями вложенности и в каталоге было более 1500 категорий о_О
Меню