Đây là phiên bản "thân thiện với nhà phát triển" của " một truy vấn , không đệ quy "giải pháp cho vấn đề này.
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;
Bạn chỉ cần hiểu cách sử dụng biến $ parent_stack.
Đó là ngăn xếp "LIFO" (Lần vào cuối, Lần ra trước) - hình ảnh trong bài viết Wikipedia có giá trị hàng nghìn từ: http://en.wikipedia.org/wiki/LIFO_%28computing%29
Khi một tùy chọn menu có các tùy chọn phụ, chúng tôi lưu trữ ID gốc của nó trong ngăn xếp:
array_push( $parent_stack, $parent );
Và sau đó, chúng tôi ngay lập tức cập nhật $ parent, làm cho nó trở thành ID tùy chọn menu hiện tại:
$parent = $option['value']['id'];
Sau khi chúng tôi lặp lại tất cả các tùy chọn phụ của nó, chúng tôi có thể quay lại cấp trước đó:
$parent = array_pop( $parent_stack );
Đây là lý do tại sao chúng tôi lưu trữ ID gốc trong ngăn xếp!
Đề xuất của tôi là:hãy chiêm nghiệm đoạn mã ở trên và hiểu nó.
Chúng tôi hoan nghênh các câu hỏi!
Một trong những ưu điểm mà tôi thấy trong cách tiếp cận này là nó loại bỏ nguy cơ đi vào vòng lặp vô hạn, có thể xảy ra khi sử dụng đệ quy.