PHP+MySQL实现无限下级分类树:递归与引用法对比

小石头
小石头
发布时间:2026-10-13| 4人浏览过
原创

探讨在 PHP 和 MySQL 环境下构建无限下级分类树的策略,涵盖递归查询实现与基于数组引用的一次性数据处理方法。

核心逻辑与准备条件

无限下级分类(通常称为无限极分类或树形结构)的核心在于如何建立分类之间的上下级关系。实现这一目标通常需要满足以下基础:

  • 数据库表设计:包含唯一标识字段 id、分类名称 name 以及父级 ID pid。顶级分类的 pid 通常设为 0。
  • 数据结构目标:将扁平的一维数据转化为嵌套的树状结构,通常表现为数组中增加 children 键来存储子节点。

第一种方案:递归查询输出(适用于小规模数据)

这种方法思路直观,即每发现一个节点,就去数据库查询其是否有子节点,以此类推。其优点是代码逻辑简单,缺点是存在大量重复 SQL 查询,性能较差。

示例:递归函数获取树形 JSON

定义函数 get_array($user_id, $top),其中 $top=1 表示开始遍历顶层。该函数执行 SQL 查询,组装数组并递归调用自身。

function get_array($user_id,$top=0){
  global $mysql,$_G;
  // 注意:生产环境请确保变量已正确转义防止 SQL 注入
  $sql = "select user_id as name from `{spreads_users}` where spreads_userid='{$user_id}'";
  $rows = $mysql->db_fetch_arrays($sql);
  
  if($top==1){
    $arr[0]['name']=$user_id;
    $arr[0]['children']=array();
  }
  $top=$top+1;
  
  foreach ($rows as $key=>$value)
  {
      $r = get_array($value['name']); // 递归调用,查询下级
      $arr[0]['children'][$key]['name']= $value['username']; 
      if(is_array($r)){
          $arr[0]['children'][$key]['children']= $r[0]['children'];
      }
      $i++;
  }
  return $arr;
}

// 调用示例:从 ID 为 1000 的顶级分类开始
$list = get_array("1000",1); 
echo 'var data='.json_encode($list);

第二种方案:引用法构建(高效推荐)

为了避免 N+1 次 SQL 查询的性能陷阱,最佳实践是先查出所有分类数据到 PHP 内存中,然后进行一次遍历构建树结构。这利用了 PHP 引用机制(&),以极低的 CPU 开销完成层级映射。

Step 1: 构建原始一维数组

假设从数据库中拉取出的数据如下(也可在实际应用中替换为真实的 DB 查询结果):

$categories = array(
  array('id'=>1,'name'=>'电脑','pid'=>0),
  array('id'=>2,'name'=>'手机','pid'=>0),
  array('id'=>3,'name'=>'笔记本','pid'=>1),
  array('id'=>4,'name'=>'台式机','pid'=>1),
  array('id'=>5,'name'=>'智能机','pid'=>2),
  array('id'=>6,'name'=>'功能机','pid'=>2),
  array('id'=>7,'name'=>'超级本','pid'=>3),
  array('id'=>8,'name'=>'游戏本','pid'=>3),
);

Step 2: 初始化索引数组

将 id 作为 key,同时初始化空的 children 数组:

$tree = array();
foreach($categories as $category){
  $tree[$category['id']] = $category;
  $tree[$category['id']]['children'] = array();
}

Step 3: 利用引用归并子节点

这是最关键的一步。再次遍历数组,如果当前节点的 pid 不为 0,则将其引用添加到父节点的 children 数组中:

// 利用引用,一次遍历即可形成树形结构
foreach ($tree as $k=>$item) {
  if ($item['pid'] != 0) {
    // 关键:使用 &$tree[$k] 将引用指向原元素,而非复制副本
    $tree[$item['pid']]['children'][] = &$amp;$tree[$k];
  }
}

执行后,$tree[1] 的 children 中将包含“笔记本”和“台式机”的结构,且它们内部会继续包含更深层的引用。

其他常见写法辨析

部分旧代码中使用了字符串拼接模拟树形缩进(如 │ │ └─),这种做法属于前端显示层面的格式化,并非标准的数据结构处理:

function sort_list($str,$fatherid,$count){
  // ... 查询数据 ...
  for($n = 1 ; $n < $count ; $n++){
     $name.="│ "; // 层级前缀
  }
  // ... 组合字符串并递归 ...
  $str = $this->sort_list($str,$rs[$i][id],$temp);
  return $str;
}

这种方法的缺点是无法直接获得可操作的树形对象(JSON/Array),不利于后续的前端组件渲染(如 Vue/React TreeView)或二次加工。

性能优化与总结

  • 缓存策略:分类数据通常变动频率低。建议在应用层将生成的树形数组序列化保存至 Redis 或文件缓存中,避免每次请求都进行 PHP 内存计算。
  • 数据库路径记录:对于超大型分类库,除了父子指针法(PID),还可考虑维护 path 字段(如 /1/3/7/)以加速特定深度的过滤操作。
  • 适用场景:递归查询仅适合极少量级(如几十级)且频繁变动的场景;引用法(全量加载后处理)是 Web 开发中最稳健的标准解法。
以上就是PHP结合MySQL实现无限下级分类树输出的详细内容,更多关于PHP程序设计技巧与树形数据结构处理的资料请关注本站其它相关文章!
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。