You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用PHP将数据库查询返回的数组转换为树形结构

PHP 数组转指定树形结构实现方案

问题说明

我用PHP开发,数据库查询返回一个数组,需要根据其中的dropdown_id(层级节点标识)和dropdown_where(父节点关联标识)转换为指定的树形结构,推测需要用递归函数,但不清楚具体实现方式,求实现方法和方案建议。

原始数组

$originalArray = [
    [
        'nome' => 'adicionar',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => '',
        'tipo_sub_funcao' => 3,
        'check_dropdown' => '',
        'posicao' => 1,
        'dropdown_id' => 1,
        'dropdown_where' => '',
        'pagina' => 'ddc_funcoes'
    ],
    [
        'nome' => 'drop teste 1',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'teste',
        'tipo_sub_funcao' => 3,
        'check_dropdown' => '',
        'posicao' => 5,
        'dropdown_id' => '1.1',
        'dropdown_where' => 1,
        'pagina' => 'ddc_funcoes'
    ],
    [
        'nome' => 'deletar',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'funcoes_deletar[sub_funcao]',
        'tipo_sub_funcao' => 1,
        'check_dropdown' => '',
        'posicao' => 3,
        'dropdown_id' => 3,
        'dropdown_where' => '',
        'pagina' => 'ddc_funcoes'
    ],
    [
        'nome' => 'editar',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'funcoes_editar[sub_funcao]',
        'tipo_sub_funcao' => 1,
        'check_dropdown' => '',
        'posicao' => 2,
        'dropdown_id' => 2,
        'dropdown_where' => '',
        'pagina' => 'ddc_funcoes'
    ],
    [
        'nome' => 'sub funcao teste 1',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'teste',
        'tipo_sub_funcao' => 1,
        'check_dropdown' => '',
        'posicao' => 4,
        'dropdown_id' => '',
        'dropdown_where' => 1,
        'pagina' => 'ddc_funcoes'
    ],
    [
        'nome' => 'sub funcao teste 2',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'teste',
        'tipo_sub_funcao' => 1,
        'check_dropdown' => '',
        'posicao' => 1,
        'dropdown_id' => '',
        'dropdown_where' => '1.1',
        'pagina' => 'ddc_funcoes'
    ],
    [
        'nome' => 'sub funcao',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'funcoes_adicionar[sub_funcao]',
        'tipo_sub_funcao' => 1,
        'check_dropdown' => 'adicionar',
        'posicao' => 1,
        'dropdown_id' => '',
        'dropdown_where' => 1,
        'pagina' => 'ddc_funcoes'
    ],
    [
        'nome' => 'sub funcao dropdown',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'funcoes_adicionar[sub_funcao_dropdown]',
        'tipo_sub_funcao' => 1,
        'check_dropdown' => 'adicionar',
        'posicao' => 3,
        'dropdown_id' => '',
        'dropdown_where' => 1,
        'pagina' => 'ddc_funcoes'
    ],
    [
        'nome' => 'sub funcao tab',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'funcoes_adicionar[sub_funcao_tab]',
        'tipo_sub_funcao' => 1,
        'check_dropdown' => 'adicionar',
        'posicao' => 2,
        'dropdown_id' => '',
        'dropdown_where' => 1,
        'pagina' => 'ddc_funcoes'
    ]
];

期望输出

$expectedTree = [
    [
        'nome' => 'adicionar',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => '',
        'tipo_sub_funcao' => 3,
        'check_dropdown' => '',
        'posicao' => 1,
        'dropdown_id' => 1,
        'dropdown_where' => '',
        'pagina' => 'ddc_funcoes',
        'sub_funcao_arr' => [
            [
                'nome' => 'sub funcao',
                'sub_funcao' => 'sub_funcao',
                'nome_funcao' => 'funcoes_adicionar[sub_funcao]',
                'tipo_sub_funcao' => 1,
                'check_dropdown' => 'adicionar',
                'posicao' => 1,
                'dropdown_id' => '',
                'dropdown_where' => 1,
                'pagina' => 'ddc_funcoes'
            ],
            [
                'nome' => 'sub funcao dropdown',
                'sub_funcao' => 'sub_funcao',
                'nome_funcao' => 'funcoes_adicionar[sub_funcao_dropdown]',
                'tipo_sub_funcao' => 1,
                'check_dropdown' => 'adicionar',
                'posicao' => 3,
                'dropdown_id' => '',
                'dropdown_where' => 1,
                'pagina' => 'ddc_funcoes'
            ],
            [
                'nome' => 'sub funcao tab',
                'sub_funcao' => 'sub_funcao',
                'nome_funcao' => 'funcoes_adicionar[sub_funcao_tab]',
                'tipo_sub_funcao' => 1,
                'check_dropdown' => 'adicionar',
                'posicao' => 2,
                'dropdown_id' => '',
                'dropdown_where' => 1,
                'pagina' => 'ddc_funcoes'
            ],
            [
                'nome' => 'sub funcao teste 1',
                'sub_funcao' => 'sub_funcao',
                'nome_funcao' => 'teste',
                'tipo_sub_funcao' => 1,
                'check_dropdown' => '',
                'posicao' => 4,
                'dropdown_id' => '',
                'dropdown_where' => 1,
                'pagina' => 'ddc_funcoes'
            ],
            [
                'nome' => 'drop teste 1',
                'sub_funcao' => 'sub_funcao',
                'nome_funcao' => 'teste',
                'tipo_sub_funcao' => 3,
                'check_dropdown' => '',
                'posicao' => 5,
                'dropdown_id' => '1.1',
                'dropdown_where' => 1,
                'pagina' => 'ddc_funcoes',
                'dropdown' => [
                    [
                        'nome' => 'sub funcao teste 2',
                        'sub_funcao' => 'sub_funcao',
                        'nome_funcao' => 'teste',
                        'tipo_sub_funcao' => 1,
                        'check_dropdown' => '',
                        'posicao' => 1,
                        'dropdown_id' => '',
                        'dropdown_where' => '1.1',
                        'pagina' => 'ddc_funcoes'
                    ]
                ]
            ]
        ]
    ],
    [
        'nome' => 'editar',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'funcoes_editar[sub_funcao]',
        'tipo_sub_funcao' => 1,
        'check_dropdown' => '',
        'posicao' => 2,
        'dropdown_id' => 2,
        'dropdown_where' => '',
        'pagina' => 'ddc_funcoes'
    ],
    [
        'nome' => 'deletar',
        'sub_funcao' => 'sub_funcao',
        'nome_funcao' => 'funcoes_deletar[sub_funcao]',
        'tipo_sub_funcao' => 1,
        'check_dropdown' => '',
        'posicao' => 3,
        'dropdown_id' => 3,
        'dropdown_where' => '',
        'pagina' => 'ddc_funcoes'
    ]
];

实现代码

步骤1:按父节点分组

先把所有节点按dropdown_where分组,避免递归中重复遍历原数组,提升效率:

// 分组:键是父节点的dropdown_id(顶级节点用root标识),值是子节点列表
$grouped = [];
foreach ($originalArray as $item) {
    $parentId = $item['dropdown_where'] ?: 'root';
    if (!isset($grouped[$parentId])) {
        $grouped[$parentId] = [];
    }
    $grouped[$parentId][] = $item;
}

步骤2:递归构建树形结构

编写递归函数,处理每个节点并添加对应的子节点,同时按posicao排序保证顺序:

function buildTree($nodes, $grouped) {
    $tree = [];
    foreach ($nodes as $node) {
        $currentNode = $node;
        $nodeId = $node['dropdown_id'];
        
        // 获取当前节点的所有子节点
        $children = $grouped[$nodeId] ?? [];
        $subFuncaoArr = [];
        
        foreach ($children as $child) {
            $childNode = $child;
            // 如果子节点有dropdown_id,递归处理它的子节点并放入dropdown字段
            if (!empty($child['dropdown_id'])) {
                $childDropdown = $grouped[$child['dropdown_id']] ?? [];
                if (!empty($childDropdown)) {
                    $childNode['dropdown'] = buildTree($childDropdown, $grouped);
                }
            }
            $subFuncaoArr[] = $childNode;
        }
        
        // 按posicao排序子节点
        usort($subFuncaoArr, function($a, $b) {
            return $a['posicao'] - $b['posicao'];
        });
        
        if (!empty($subFuncaoArr)) {
            $currentNode['sub_funcao_arr'] = $subFuncaoArr;
        }
        
        $tree[] = $currentNode;
    }
    
    // 顶级节点按posicao排序
    usort($tree, function($a, $b) {
        return $a['posicao'] - $b['posicao'];
    });
    
    return $tree;
}

// 获取顶级节点并构建树形结构
$topNodes = $grouped['root'] ?? [];
$resultTree = buildTree($topNodes, $grouped);

// 输出结果查看
echo '<pre>';
print_r($resultTree);
echo '</pre>';

方案建议

  1. 分组优化:先按父节点ID分组,将时间复杂度从O(n²)降至O(n log n)(主要为排序开销),大幅提升处理效率。
  2. 排序逻辑:在递归过程中按posicao字段排序,保证输出顺序与期望一致;也可在数据库查询时直接按dropdown_where和posicao排序,减少PHP端处理。
  3. 空值处理:注意判断dropdown_id和dropdown_where的空值情况,避免数组索引错误。
  4. 数据量优化:若数据量较大,可考虑使用嵌套集合模型等树形数据存储方案,优化数据库查询和结构转换逻辑。

内容的提问来源于stack exchange,提问作者lucca.germano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 21:05:25