首页 > 解决方案 > 将表与自身连接并显示在屏幕上

问题描述

这是我的桌子

row_id | category   | parent_id
1      | News       | 0
2      | Toys       | 0
3      | national   | 1
4      | local      | 1

parent_id = 0 的行是类别, parent_id != 0 的行是子类别

这就是我希望他们在我的网站上使用 PHP 在我的屏幕上显示的方式

+news
 - national
 - local
+toys
 - ...
 - ...
+ ...

因为我也不能让它与 PHP 一起工作,

标签: phpmysqlsql

解决方案


由于 OP 没有提到是否需要立即打印菜单或返回一串 HTML,这就是我将使用一个 SQL 查询并使用 PHP 递归函数处理它的方式。

请注意,有很多方法可以做到这一点,我只是向您展示其中一种方法。

<?php
// Replace this with your MySQL result
$data = [
    [
        'row_id' => 1,
        'category' => 'News',
        'parent_id' => 0,
    ],
    [
        'row_id' => 2,
        'category' => 'Toys',
        'parent_id' => 0,
    ],
    [
        'row_id' => 3,
        'category' => 'national',
        'parent_id' => 1,
    ],
    [
        'row_id' => 4,
        'category' => 'local',
        'parent_id' => 1,
    ],
];

/**
 * Print the menu recursively
 */
function printRecursive($currentMenuItem, $currentParentID = 0, $menuListInParentIDs) {

    if($currentMenuItem['parent_id'] == $currentParentID) {
        echo "<li>{$currentMenuItem['category']}</li>";

        if(isset($menuListInParentIDs[$currentMenuItem['row_id']])) {
            $children = $menuListInParentIDs[$currentMenuItem['row_id']];

            echo "<ul>";

            foreach($children as $childMenuItem) {
                printRecursive($childMenuItem, $childMenuItem['parent_id'], $menuListInParentIDs);
            }

            echo "</ul>";
        }
    }
}

// First let's group the menu with parent ID as it's key to make it easier to loop
$dataToKey = [];
foreach($data as $item) {
    if(!isset($dataToKey[$item['parent_id']])) {
        $dataToKey[$item['parent_id']] = [];
    }
    $dataToKey[$item['parent_id']][] = $item;
}

// Now let's render
echo "<ul>";
foreach($data as $item) {
    printRecursive($item, 0, $dataToKey);
}
echo "</ul>";

解释来了:

我解决这个问题的方法是将菜单项列表分组到parent_id列表中。

如果您尝试print_r($dataToKey),它将显示以下内容:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [row_id] => 1
                    [category] => News
                    [parent_id] => 0
                )

            [1] => Array
                (
                    [row_id] => 2
                    [category] => Toys
                    [parent_id] => 0
                )

        )

    [1] => Array
        (
            [0] => Array
                (
                    [row_id] => 3
                    [category] => national
                    [parent_id] => 1
                )

            [1] => Array
                (
                    [row_id] => 4
                    [category] => local
                    [parent_id] => 1
                )

        )

)

通过这样做,您可以知道哪些菜单项属于parent_id0,哪些属于 1,以此类推。

我为什么要这样做?

我这样做是为了让我们的递归函数不会浪费时间一遍又一遍地循环数据源。

现在我们有了这个辅助变量,我们可以开始执行递归函数了。

这是我们的递归函数

/**
 * Print the menu recursively
 */
function printRecursive($currentMenuItem, $currentParentID = 0, $menuListInParentIDs) {

    if($currentMenuItem['parent_id'] == $currentParentID) {
        echo "<li>{$currentMenuItem['category']}</li>";

        if(isset($menuListInParentIDs[$currentMenuItem['row_id']])) {
            $children = $menuListInParentIDs[$currentMenuItem['row_id']];

            echo "<ul>";

            foreach($children as $childMenuItem) {
                printRecursive($childMenuItem, $childMenuItem['parent_id'], $menuListInParentIDs);
            }

            echo "</ul>";
        }
    }
}

此函数的作用是获取当前菜单项,检查此特定菜单项是否是给定父 ID 的一部分$currentParentID。如果是,则打印它,否则不做任何事情。

打印后,它会使用我们之前创建的变量来检查是否有其他菜单项是当前菜单的子项,该变量来自$dataToKey.

如果至少有一个子菜单项,则调用相同的递归函数来打印当前子菜单项,然后检查它是否有孙子菜单项,依此类推。

现在让我们打印它

我们通过调用以下代码片段来启动它。

// Now let's render
echo "<ul>";
foreach($data as $item) {
    printRecursive($item, 0, $dataToKey);
}
echo "</ul>";

您可能会注意到其中包含第二个参数0,因为我们希望从最顶部开始打印。如果要从parent_id1 开始打印,只需将其更改为1.

---

我希望这对您有意义,因为理解递归函数的工作原理可能非常具有挑战性。

还有其他方法吗?

有!有不同的方法可以做到这一点。发现不同的方法来实现它是你的挑战。把它想象成一个很好的锻炼。

这是执行递归函数的最佳方法吗?

可能不会,我相信其他人可以想出比我更好的方法。但是,如果它可以工作并且可以完成工作,那么在您需要对其进行优化之前就很好了。


推荐阅读