Ето „удобна за разработчиците“ версия на „една заявка , без рекурсия " решение за този проблем.
SQL :
SELECT id, parent_id, title, link, position FROM menu_item ORDER BY parent_id, position;
PHP :
$html = '';
$parent = 0;
$parent_stack = array();
// $items contains the results of the SQL query
$children = array();
foreach ( $items as $item )
$children[$item['parent_id']][] = $item;
while ( ( $option = each( $children[$parent] ) ) || ( $parent > 0 ) )
{
if ( !empty( $option ) )
{
// 1) The item contains children:
// store current parent in the stack, and update current parent
if ( !empty( $children[$option['value']['id']] ) )
{
$html .= '<li>' . $option['value']['title'] . '</li>';
$html .= '<ul>';
array_push( $parent_stack, $parent );
$parent = $option['value']['id'];
}
// 2) The item does not contain children
else
$html .= '<li>' . $option['value']['title'] . '</li>';
}
// 3) Current parent has no more children:
// jump back to the previous menu level
else
{
$html .= '</ul>';
$parent = array_pop( $parent_stack );
}
}
// At this point, the HTML is already built
echo $html;
Просто трябва да разберете използването на променливата $parent_stack.
Това е стек "LIFO" (Last In, First Out) - изображението в статията на Wikipedia струва хиляда думи:http://en.wikipedia.org/wiki/LIFO_%28computing%29
Когато опция от менюто има подопции, ние съхраняваме нейния родителски идентификатор в стека:
array_push( $parent_stack, $parent );
И след това незабавно актуализираме $parent, като го правим текущия идентификатор на опцията на менюто:
$parent = $option['value']['id'];
След като завъртахме всички негови подопции, можем да се върнем обратно към предишното ниво:
$parent = array_pop( $parent_stack );
Ето защо съхранихме родителския идентификатор в стека!
Моето предложение е:разгледайте кодовия фрагмент по-горе и го разберете.
Въпросите са добре дошли!
Едно от предимствата, които виждам в този подход, е, че елиминира риска от влизане в безкраен цикъл, което може да се случи, когато се използва рекурсия.