PHP使用传引用思想实现无限级分类的方法

宋时安
宋时安
发布时间:2026-10-13 | 2人浏览过
原创

在Web开发中,无限级分类是常见需求,通常表现为评论楼层、多级菜单或组织架构等。传统做法多依赖递归查询数据库或深度优先搜索,但在内存中对已获取的一维数组进行重组时,利用PHP的传引用(Reference)机制可以显著简化逻辑并提升性能。

结果与目标

我们的目标是将一个扁平的一维分类数组(包含 id 和 pid),转换为嵌套的树形数组结构。例如,将以下线性数据存储:

  • id: 1, pid: 0, name: "四川"
  • id: 2, pid: 0, name: "重庆"
  • id: 3, pid: 1, name: "成都"
  • id: 4, pid: 1, name: "绵阳"
  • id: 5, pid: 3, name: "高新区"

最终输出为层级分明的嵌套结构,其中“成都”作为“四川”的子节点,“高新区”作为“成都”的子节点。

准备条件

要实现这一功能,需要满足以下条件:

  1. 数据源:必须是从数据库查询出的关联数组,至少包含唯一标识符(如 id)和父级标识符(如 pid)。
  2. 环境:标准的PHP运行环境,支持引用赋值操作符 &。
  3. 数据结构认知:理解PHP数组是按值传递还是按引用传递的区别。

真实操作顺序

第1步:构建基于ID的快速查找索引

为了确保在后续遍历中能迅速定位任意元素及其父元素,首先应将原始数组转化为以 id 为键的新数组。这样可以通过 $items[$id] 直接访问对应数据,时间复杂度为 O(1)。

入口:接收原始一维数组 $orig。

动作:

$items = array();
foreach ($orig as $key => $value) {
    // 确保即使原数组下标不连续,也能通过id精准定位
    $items[$value['id']] = $value;
}

第2步:初始化结果容器

创建一个空数组 $tree,用于存放最终生成的根节点(即 pid == 0 的分类)。

第3步:遍历并挂载子节点(核心逻辑)

再次遍历刚才建立的索引数组 $items。对于每个元素,检查其 pid:

  1. 判断根节点:如果 $item['pid'] == 0,说明这是顶级分类,将其引用加入 $tree 数组末尾。
  2. 判断非根节点:
    • 若存在 $items[$item['pid']](即父节点已在之前的遍历中被处理或本身就是存在的),则将该元素的引用追加到父节点的 'child' 字段中。
    • 关键点:使用 &$items[$key] 而不是复制整个数组对象。这意味着修改子节点内容也会反映在父节点的引用中,且节省内存开销。
  3. 异常处理(可选):如果遇到 pid 指向的元素不存在于数据集中(可能是脏数据或尚未加载),可根据业务需求将其单独存入 $tree 或忽略。在本示例中,若父节点不存在,暂时将其视为孤立项加入顶层,但这通常应配合数据清洗使用。

重要参数:引用符号 &。

可观察的完成状态:当循环结束,$tree 中包含所有根节点,且每个根节点内部通过 child 键链接着对应的子级引用,形成完整的树状结构。

/**
 * 使用传引用思想生成无限级分类树
 * @param array $orig 原始一维分类数据
 * @return array 嵌套的树形结构
 */
public static function get_tree($orig) {
    // 1. 建立 ID -> Data 的映射表,方便快速查找
    $items = array();
    foreach ($orig as $key => $value) {
        $items[$value['id']] = $value;
    }

    $tree = array();

    // 2. 遍历映射表组装树
    foreach ($items as $key => $item) {
        if ($item['pid'] == 0) { 
            // 顶级分类,直接放入结果集
            $tree[] = &$items[$key];
        } else {
            // 检查父节点是否存在
            if (isset($items[$item['pid']])) {
                // 存在父节点,利用引用将当前项挂到父节点的 child 数组中
                $items[$item['pid']]['child'][] = &$items[$key];
            } else {
                // 父节点不存在(数据异常或丢失),视情况处理
                // 此处选择放入顶层,防止数据丢失
                $tree[] = &$items[$key];
            }
        }
    }

    return $tree;
}

完成判断

调用上述函数后,返回的数组即为树形结构。可通过打印 JSON 格式验证:

print_r(json_encode(get_tree($original_data), JSON_PRETTY_PRINT));

检查输出中是否包含预期的层级嵌套关系,以及是否没有重复引用导致的死循环问题。

简要总结

相比传统的递归查询数据库方式,PHP传引用法主要优势在于:

  • 性能:一次查询获取所有数据,在内存中进行O(N)时间的组装,避免了N次数据库交互。
  • 简洁:代码逻辑直观,无需维护复杂的递归栈。

需要注意的是,引用赋值要求 PHP 版本支持,且在后续对树形结构的遍历时,需留意引用的可变性。以上就是利用PHP传引用思想实现无限级分类的详细内容,更多关于PHP高性能数据处理技巧的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表