
在许多应用场景中,数据通常以扁平化的形式存储,例如数据库中的分类、菜单或组织结构,它们通过一个 id 字段和一个 parentid 字段来表示父子关系。然而,为了更好地展示或操作这些数据,我们常常需要将其转换为具有层级关系的树形结构,其中每个父节点包含一个子节点数组(例如 pages)。
例如,我们可能拥有以下结构的数据:
$indexes = [
    ['id' => 1, 'parentid' => 0, 'route' => 'root', 'title' => 'root'],
    ['id' => 2, 'parentid' => 1, 'route' => 'parent', 'title' => 'parent'],
    ['id' => 3, 'parentid' => 2, 'route' => 'child', 'title' => 'child']
];我们期望将其转换为如下的嵌套结构:
$index = [
    [
        'id' => 1,
        'pages' => [
            [
                'id' => 2,
                'pages' => [
                    [
                        'id' => 3
                    ]
                ]
            ]
        ]
    ]
];递归是解决这类问题的强大工具。其核心思想是:一个函数调用自身来解决问题的子集,直到达到基本情况(即没有更多子节点)。
为了构建树形结构,我们可以定义一个递归函数,该函数接收整个扁平数组和当前需要查找的父节点ID。函数内部会遍历数组,找出所有直接子节点,然后对每个子节点递归调用自身,以查找它们的子节点。
立即学习“PHP免费学习笔记(深入)”;
最初的尝试可能如下所示:
function buildSubs(array $elms, int $parentId = 0)
{
    $branch = [];
    foreach ($elms as $elm) {
        if ($elm['parentid'] == $parentId) {
            $children = buildSubs($elms, $elm['id']);
            if ($children) {
                // 错误:这里将 'pages' 键添加到了整个 $elms 数组,而不是当前的 $elm 元素
                $elms['pages'] = $children; 
            }
            $branch[] = $elm;
        }
    }
    return $branch;
}上述代码存在一个关键错误:在找到子节点后,试图通过 $elms['pages'] = $children; 将子节点数组赋给 $elms。然而,$elms 是传入函数的整个原始数组的副本,而不是当前正在处理的 $elm 元素。这导致了子节点数组没有被正确地附加到其父元素上。
正确的做法是将子节点数组附加到当前循环中的 $elm 元素上,即 $elm['pages'] = $children;。
修正上述错误并考虑起始父节点ID(通常根节点的 parentid 为0或null)后,我们可以得到一个功能完善的递归函数:
<?php
/**
 * 将扁平数组转换为嵌套树形结构
 *
 * @param array $elements 包含 id 和 parentid 的扁平数据数组
 * @param int $parentId 当前需要查找的父节点ID
 * @return array 构建好的树形分支
 */
function buildTree(array $elements, int $parentId = 0): array
{
    $branch = []; // 用于存储当前层级的节点
    foreach ($elements as $element) {
        if ($element['parentid'] == $parentId) {
            // 递归查找当前元素的子节点
            $children = buildTree($elements, $element['id']);
            // 如果存在子节点,则将其添加到当前元素的 'pages' 键下
            if (!empty($children)) {
                $element['pages'] = $children; // 关键修正:将 'pages' 赋给当前 $element
            }
            // 将处理好的元素添加到当前层级的 $branch 中
            $branch[] = $element;
        }
    }
    return $branch;
}
// 示例数据
$data = [
    ['id' => 1, 'parentid' => 0, 'route' => 'root', 'title' => 'root'],
    ['id' => 2, 'parentid' => 1, 'route' => 'parent', 'title' => 'parent'],
    ['id' => 3, 'parentid' => 2, 'route' => 'child', 'title' => 'child'],
    ['id' => 4, 'parentid' => 1, 'route' => 'sibling', 'title' => 'sibling'], // 添加一个同级节点
    ['id' => 5, 'parentid' => 0, 'route' => 'another_root', 'title' => 'another_root'] // 添加另一个根节点
];
// 从 parentid = 0 开始构建整个树
$tree = buildTree($data, 0);
// 打印结果
echo "<pre>";
print_r($tree);
echo "</pre>";
?>执行上述代码,将得到以下结构化的输出:
Array
(
    [0] => Array
        (
            [id] => 1
            [parentid] => 0
            [route] => root
            [title] => root
            [pages] => Array
                (
                    [0] => Array
                        (
                            [id] => 2
                            [parentid] => 1
                            [route] => parent
                            [title] => parent
                            [pages] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 3
                                            [parentid] => 2
                                            [route] => child
                                            [title] => child
                                        )
                                )
                        )
                    [1] => Array
                        (
                            [id] => 4
                            [parentid] => 1
                            [route] => sibling
                            [title] => sibling
                        )
                )
        )
    [1] => Array
        (
            [id] => 5
            [parentid] => 0
            [route] => another_root
            [title] => another_root
        )
)可以看到,id 为 1 的元素包含了 id 为 2 和 4 的子元素,而 id 为 2 的元素又包含了 id 为 3 的子元素,完美地构建了所需的嵌套树形结构。
通过递归函数将扁平的父子关系数据转换为嵌套的树形结构是PHP开发中常见的需求。理解递归的工作原理,特别是正确处理当前元素属性的赋值,是实现这一功能的关键。虽然递归方法简洁优雅,但在处理大规模数据时,也需要考虑性能和内存消耗,并根据具体情况选择或优化实现方式。掌握这种技巧,将有助于你更灵活地处理和展示具有层级关系的数据。
以上就是使用PHP递归构建嵌套树形结构:从扁平数据到层级展示的详细内容,更多请关注php中文网其它相关文章!
                        
                        PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
                
                                
                                
                                
                                
                                
                                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号