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

PHP/MySQL实现数据库树形文件夹结构转数组/JSON及代码报错排查咨询

解决文件夹树形结构构建的错误与优化方案

首先,咱们先搞定你遇到的Cannot use a scalar value as an array错误,再重新梳理整个树形结构的构建逻辑——你的代码里有几个关键的逻辑和结构理解偏差,我一步步给你讲清楚。

错误原因分析

你在buildTree里写的$tnode['folder']['fold_id']['subfolders']是问题的核心:fold_id是一个数字(比如1、2),属于标量值,不是数组,你试图把它当成数组去访问['subfolders'],自然会抛出这个错误。这是因为你搞错了节点的结构层次,subfolders应该是folder对象下的属性,而不是fold_id的子属性。

除此之外,你当前的递归构建逻辑也比较混乱,比如初始化树形数组的方式、递归传递参数的逻辑都不符合目标结构的要求,而且你给出的目标JSON还存在一个潜在问题:JSON对象不允许重复键,你示例里的sub_folders下有多个folder键,这在JSON解析时会被覆盖,是不合法的,后面我会给出修正后的合理结构。

正确的实现方案

我会给你一套更清晰、高效的实现方式,用ID映射的方式替代递归遍历,这种方法不仅容易理解,还能避免递归带来的性能问题。

重构后的getFolderTree函数

public function getFolderTree($foldID): string {
    $sql = <<<SQL
SELECT 1 oby, fold_id, fold_name, fold_parent_fold_id
FROM (SELECT * FROM folders ORDER BY fold_parent_fold_id, fold_id) items_sorted,
(SELECT @iv := ?) initialisation
WHERE find_in_set(fold_parent_fold_id, @iv) AND length(@iv := concat(@iv, ',', fold_id))
UNION
SELECT 0 oby, fold_id, fold_name, fold_parent_fold_id
FROM folders WHERE fold_id = ?
ORDER BY 1, 4, 3
SQL;
    $rows = $this->db->query($sql, $foldID, $foldID)->fetchAll();

    // 第一步:建立ID到节点的映射,预先初始化sub_folders为空数组
    $folderMap = [];
    foreach ($rows as $row) {
        $folderMap[$row['fold_id']] = [
            'folder' => [
                'fold_id' => $row['fold_id'],
                'fold_name' => $row['fold_name'],
                'fold_parent_fold_id' => $row['fold_parent_fold_id'],
                'sub_folders' => []
            ]
        ];
    }

    // 第二步:遍历节点,将每个节点添加到父节点的sub_folders中
    $rootNode = null;
    foreach ($folderMap as $folderId => $node) {
        $parentId = $node['folder']['fold_parent_fold_id'];
        
        if ($parentId === null) {
            // 找到根节点
            $rootNode = $node;
        } else {
            // 将当前节点追加到父节点的sub_folders数组中
            $folderMap[$parentId]['folder']['sub_folders'][] = $node;
        }
    }

    // 生成格式化后的JSON(符合JSON规范,无重复键)
    return json_encode($rootNode, JSON_PRETTY_PRINT);
}

代码说明

  1. ID映射构建:先把数据库返回的扁平数据转换成以fold_id为键的关联数组,每个节点都预先初始化sub_folders为空数组,彻底避免了标量访问的错误。
  2. 树形结构组装:遍历每个节点,根据fold_parent_fold_id找到它的父节点,把当前节点添加到父节点的sub_folders数组中——这种方式比递归更直观,也更容易调试。
  3. 修正JSON结构:把原目标中重复的folder键改成数组形式,这符合JSON规范,不会出现解析时被覆盖的问题。最终生成的JSON结构如下(和你的需求一致但更合法):
{
  "folder": {
    "fold_id": 1,
    "fold_name": "top",
    "fold_parent_fold_id": null,
    "sub_folders": [
      {
        "folder": {
          "fold_id": 2,
          "fold_name": "subtop1",
          "fold_parent_fold_id": 1,
          "sub_folders": []
        }
      },
      {
        "folder": {
          "fold_id": 3,
          "fold_name": "subtop2",
          "fold_parent_fold_id": 1,
          "sub_folders": [
            {
              "folder": {
                "fold_id": 4,
                "fold_name": "subsubtop1",
                "fold_parent_fold_id": 3,
                "sub_folders": []
              }
            }
          ]
        }
      }
    ]
  }
}

为什么原来的buildTree函数不可行?

除了标量访问的错误,原来的递归逻辑还有这些问题:

  • 递归传递的参数不符合节点结构,每次递归都没有正确找到父节点的位置。
  • 初始化tree_array的方式混乱,比如一开始把$dirs赋值给tree_array,后续递归无法正确维护整个树形结构。
  • 试图在标量属性上添加数组,完全搞错了节点的层次结构。

如果你坚持要用递归实现,也可以基于上面的ID映射逻辑调整,但显然ID映射的方式更简单高效。

内容的提问来源于stack exchange,提问作者TenG

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 14:12:46