Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
利用PHP递归构建树形数据结构教程_创想鸟

利用PHP递归构建树形数据结构教程

利用PHP递归构建树形数据结构教程

本文详细介绍了如何使用PHP递归函数将扁平化的父子关系数组转换为嵌套的树形结构。通过分析常见错误并提供修正后的代码示例,本教程旨在帮助开发者高效地处理层级数据,实现如菜单、分类或评论回复等场景的动态生成和展示。

1. 理解树形数据结构及其应用场景

在web开发中,我们经常需要处理具有层级关系的数据,例如网站导航菜单、商品分类、组织架构图或评论回复列表。这类数据通常存储在数据库中,以扁平化的形式呈现,即每条记录包含一个 id 和一个 parentid 来标识其父子关系。然而,为了更好地展示或操作这些数据,我们往往需要将其转换为嵌套的、树形的结构。

例如,我们有以下扁平化的数据数组,它描述了一个简单的层级关系:

$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']];

我们的目标是将其转换为如下所示的嵌套结构,其中子元素被封装在父元素的 pages 数组中:

$index=[  [    'id'=>1,    'pages' => [       [         'id'=>2,         'pages' => [          [            'id'=>3          ]     ]];

2. 递归构建树形结构的核心思想

递归是一种强大的编程技术,它允许函数调用自身来解决问题。在构建树形结构时,递归的核心思想是:

查找直接子元素: 对于给定父ID,遍历所有元素,找出直接以该父ID为 parentid 的子元素。递归处理子元素: 对于每个找到的子元素,以其自身的 id 作为新的父ID,再次调用函数,查找其下属的子元素。构建层级: 将递归调用返回的子元素集合添加到当前元素的特定键(例如 pages)下。

3. 常见错误分析与修正

在尝试实现上述逻辑时,开发者可能会遇到一些常见的错误。以下是原始代码片段及其存在的问题:

立即学习“PHP免费学习笔记(深入)”;

function buildSubs(array $elms, int $parentId = 0){    $branch = [];    foreach ($elms as $elm) {        if ($elm['parentid'] == $parentId) {            $children = buildSubs($elms, $elm['id']);            if ($children) {                // 错误点1:这里应该是 $elm['pages'] = $children; 而不是 $elms['pages']                $elms['pages'] = $children;             }            $branch[] = $elm;        }    }    return $branch;}// 错误点2:如果想构建完整的树,初始 $parentId 应该从根节点(通常是0)开始$parentid = 1; $indexes = buildSubs($indexes, $parentid);var_dump($indexes);

错误分析:

变量引用错误: 在 if ($children) 块中, $elms[‘pages’] = $children; 试图修改传入函数的整个 $elms 数组,而不是当前正在处理的单个元素 $elm。这导致子节点未能正确附加到其父节点上。初始父ID选择: 如果目标是构建整个树形结构(从根节点开始),那么首次调用 buildSubs 时,$parentId 应该设置为根节点的 parentid,通常是 0。如果设置为 1,则只会构建以 id=1 为根的子树。

4. 正确的递归实现

根据上述分析,我们对 buildSubs 函数进行修正,并展示如何正确调用以构建完整的树形结构:

 $elm) {        // 检查当前元素的 parentid 是否与传入的 parentId 匹配        if ($elm['parentid'] == $parentId) {            // 找到直接子元素后,递归调用 buildSubs 查找其子级            // 注意:这里传入的是完整的 $elms 数组,以便在所有元素中查找            $children = buildSubs($elms, $elm['id']);            // 如果当前元素有子级,将其添加到当前元素的 'pages' 键下            if ($children) {                $elm['pages'] = $children;            }            // 将处理后的当前元素添加到当前层级的 $branch 数组中            $branch[] = $elm;            // 可选:如果元素处理后不再需要,可以从 $elms 中移除以优化性能(对于非常大的数据集)            // unset($elms[$key]);         }    }    return $branch; // 返回当前层级的元素集合}// 原始扁平化数据$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']];// 调用函数构建完整的树形结构,从 parentid 为 0 的根节点开始$fullTree = buildSubs($indexes, 0);// 输出结果echo '
';var_dump($fullTree);echo '

';?>

代码解析:

buildSubs(array $elms, int $parentId = 0): array:函数接受完整的扁平化数组 $elms 和当前要查找的父ID $parentId。默认 $parentId 为 0,方便从根节点开始构建。$branch = [];:初始化一个空数组,用于收集当前 $parentId 下的所有直接子元素。foreach ($elms as $key => $elm):遍历所有元素。if ($elm['parentid'] == $parentId):判断当前元素是否是 $parentId 的直接子元素。$children = buildSubs($elms, $elm['id']);:递归调用。如果当前元素是直接子元素,就以它的 id 作为新的 $parentId,再次调用 buildSubs 来查找它的所有子孙。if ($children) { $elm['pages'] = $children; }:如果递归调用返回了子元素(即 $children 不为空),则将这些子元素赋值给当前元素的 pages 键。这是关键修正点,确保子元素被正确地附加到其父元素内部。$branch[] = $elm;:将处理完毕(可能已包含 pages 键)的当前元素添加到 $branch 数组中。return $branch;:返回当前层级的所有已处理元素。

预期输出:

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                                        )                                )                        )                )        ))

这个输出正是我们期望的完整树形结构。

5. 注意事项与优化

性能考量: 对于非常大的数据集(例如数万条记录),每次递归调用都遍历整个 $elms 数组可能会导致性能问题。在这种情况下,可以考虑以下优化:预处理为哈希表: 在递归开始前,将 $elms 数组转换为以 id 为键的哈希表(或关联数组),这样可以通过 id 直接访问元素,避免重复遍历。传递引用: 如果在递归过程中需要修改原始数组(例如,将已处理的元素从 $elms 中移除以减少后续遍历的范围),可以将 $elms 作为引用传递给函数。迭代法: 对于极端大数据量,非递归的迭代方法(如广度优先搜索或深度优先搜索)可能更优,但实现复杂度通常更高。内存消耗: 深度递归可能会消耗较多的栈内存。PHP的默认递归深度限制通常足以应对大多数情况,但如果层级非常深,可能需要调整 php.ini 中的 xdebug.max_nesting_level(开发环境)或考虑非递归方案。灵活性:根节点处理: 确保你的数据中有一个明确的根节点(例如 parentid = 0 或 null)以便于从顶部开始构建。子节点键名: 可以根据需求修改存储子节点的键名,例如 children、sub_items 等,只需修改 if ($children) { $elm['pages'] = $children; } 中的 pages 即可。返回数据: 如果你只需要树中特定字段(如 id 和 pages),可以在递归函数中过滤掉其他字段,或者在函数外部对结果进行后处理。

总结

通过本教程,我们学习了如何利用PHP的递归功能,将扁平化的父子关系数组转换为易于处理和展示的嵌套树形结构。理解递归的核心思想、识别并修正常见错误是掌握这一技术的关键。在实际应用中,根据数据规模和性能要求,可以进一步考虑优化策略,以构建高效、健壮的层级数据处理方案。

以上就是利用PHP递归构建树形数据结构教程的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1266333.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
PHP:高效解析带引号属性的字符串
上一篇 2025年12月10日 09:35:21
PHP中合并并汇总对象数组中指定属性的方法
下一篇 2025年12月10日 09:35:37

相关推荐

  • thinkphp函数有哪些

    thinkphp函数有哪些thinkphp函数有哪些thinkphp函数有哪些thinkphp函数有哪些

    thinkphp函数有哪些? thinkphp5.0 助手函数大全 推荐教程:thinkphp教程 load_trait:快速导入Traits,PHP5.5以上无需调用 /** * 快速导入Traits PHP5.5以上无需调用 * @param string $class trait库 * @pa…

    2026年9月25日 • 用户投稿
    100
  • 忘记iphone手机密码如何解决

    通过iCloud恢复备份(需已开启iCloud备份并能正常登录Apple ID) 在电脑浏览器中访问iCloud官网,使用与锁定iPhone关联的Apple ID和密码登录。 登录后,进入“查找我的iPhone”功能页面。 在设备列表中选择已锁定的iPhone,点击“抹掉iPhone”选项。此操作将…

    2026年9月25日
    000
  • RTX 5080整机塞进保时捷911轮毂!通过钥匙开机重启

    RTX 5080整机塞进保时捷911轮毂!通过钥匙开机重启RTX 5080整机塞进保时捷911轮毂!通过钥匙开机重启RTX 5080整机塞进保时捷911轮毂!通过钥匙开机重启RTX 5080整机塞进保时捷911轮毂!通过钥匙开机重启

    10月13日,当汽车与高性能计算相遇,会激发出怎样的创意奇迹?nvidia在最新一期geforce garage节目中揭晓了答案。 这一次,他们携手改装界传奇人物JCustom(Justin Chu),将一台完整的RTX 5080游戏主机巧妙植入保时捷911的轮毂之中,实现了汽车工艺与电脑科技的惊艳…

    2026年9月25日 • 用户投稿
    000
  • 如何在ThinkPHP6中使用Eloquent简化业务层

    随着互联网的发展,web应用程序的开发已经成为现代软件开发的核心。由于业务逻辑的复杂性,开发人员需要很多工具和技术来简化代码,提高效率。在这方面,使用eloquent orm可以大大简化业务层代码。在本文中,我们将介绍如何在thinkphp6中使用eloquent来简化业务层。 什么是Eloquen…

    用户投稿 2026年9月25日
    100
  • 苹果怎么查激活时间

    苹果怎么查激活时间苹果怎么查激活时间苹果怎么查激活时间苹果怎么查激活时间

    您可以通过以下步骤查询 Apple 设备的激活时间:1. 打开设备“设置”;2. 点按“通用”;3. 点按“关于”;4. 查找“激活于”标签即可查看激活时间。 如何查询 Apple 设备的激活时间 想知道您 Apple 设备的激活时间吗?以下是查询该信息的步骤: 步骤 1:访问设备设置 在您的 Ap…

    2026年9月25日 • 用户投稿
    000
  • 外键在MySQL数据库中的重要性和实践意义

    外键在MySQL数据库中的重要性和实践意义外键在MySQL数据库中的重要性和实践意义外键在MySQL数据库中的重要性和实践意义外键在MySQL数据库中的重要性和实践意义

    外键在MySQL数据库中的重要性和实践意义 在MySQL数据库中,外键(Foreign Key)是一种用来建立不同表之间关联关系的重要约束。外键约束确保了表与表之间的数据一致性和完整性,能够有效避免不正确的数据插入、更新或删除操作。 一、外键的重要性: 降重鸟 要想效果好,就用降重鸟。AI改写智能降…

    2026年9月25日 • 用户投稿
    100
  • 亚马逊拟再次向AI创企Anthropic投资数十亿美元

    亚马逊拟再次向AI创企Anthropic投资数十亿美元亚马逊拟再次向AI创企Anthropic投资数十亿美元亚马逊拟再次向AI创企Anthropic投资数十亿美元亚马逊拟再次向AI创企Anthropic投资数十亿美元

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 有消息透露,亚马逊正计划再度向人工智能企业Anthropic注资数十亿美元,旨在深化两家公司的战略合作关系。据悉,此次潜在的投资可能在去年11月承诺的80亿美元基础上进一步加码。 早在2024年…

    2026年9月25日 • 用户投稿
    100
  • 获取物品名称并转换为字符串时出现乱码的解决方案

    获取物品名称并转换为字符串时出现乱码的解决方案获取物品名称并转换为字符串时出现乱码的解决方案获取物品名称并转换为字符串时出现乱码的解决方案获取物品名称并转换为字符串时出现乱码的解决方案

    本文旨在解决在 Minecraft Spigot 插件开发中,获取玩家放置的物品名称并尝试将其转换为字符串时出现乱码的问题。通过分析问题原因,并提供正确的代码示例,帮助开发者避免类似错误,从而更有效地获取玩家名称。 在 Spigot 插件开发中,当玩家放置方块时,我们可能需要获取该方块对应的玩家名称…

    2026年9月25日 • 用户投稿
    100
  • Tomcat日志如何帮助排查内存泄漏

    Tomcat日志如何帮助排查内存泄漏Tomcat日志如何帮助排查内存泄漏Tomcat日志如何帮助排查内存泄漏Tomcat日志如何帮助排查内存泄漏

    Tomcat日志是诊断内存泄漏问题的关键。通过分析Tomcat日志,您可以深入了解内存使用情况和垃圾回收(GC)行为,从而有效定位和解决内存泄漏。以下是如何利用Tomcat日志排查内存泄漏: 1. GC日志分析 首先,启用详细的GC日志记录。在Tomcat启动参数中添加以下JVM选项: -XX:+P…

    2026年9月25日 • 用户投稿
    000
  • 《暗黑破坏神2:重制版》国服开测 大量功能优化

    《暗黑破坏神2:重制版》国服开测 大量功能优化《暗黑破坏神2:重制版》国服开测 大量功能优化《暗黑破坏神2:重制版》国服开测 大量功能优化《暗黑破坏神2:重制版》国服开测 大量功能优化

    今日(8月27日),暴雪旗下经典之作《暗黑破坏神2:重制版》国服正式开启不删档公测,欢迎即刻回归庇护之地,重启属于你的暗黑史诗征程。 游戏宣传视频: 《暗黑破坏神2:重制版》全面支持4K超清画质,所有3D角色模型与场景均经过精细重构,原汁原味还原像素级角色造型,搭配全新升级的粒子特效,让每位英雄的技…

    2026年9月25日 • 用户投稿
    200
  • laravel和其他框架的区别

    laravel和其他框架的区别laravel和其他框架的区别laravel和其他框架的区别laravel和其他框架的区别

    今天就为大家分享一篇laravel框架与其他框架的详细对比,具有很好的参考价值,希望对大家有所帮助。 优点:     (推荐学习:laravel开发) 1、代码比较明白易懂,跟英语句子差不多,关键词就是函数,举个例子,获取数据库中某个表的所有数据: $article=new Article;$art…

    2026年9月25日 • 用户投稿
    000
  • 尽管投资创纪录,但仅有 12% 的 AI 项目实现全面部署

    尽管投资创纪录,但仅有 12% 的 AI 项目实现全面部署尽管投资创纪录,但仅有 12% 的 AI 项目实现全面部署尽管投资创纪录,但仅有 12% 的 AI 项目实现全面部署尽管投资创纪录,但仅有 12% 的 AI 项目实现全面部署

    根据 Riverbed 最新发布的全球调查报告,企业在人工智能(AI)采用方面展现出强烈承诺,并正在对 IT 运营进行战略性重塑以支撑 AI 发展。尽管整体 AI 投资额几乎翻倍,且高达 87% 的组织表示其 AIOps 项目的投资回报已达到或超出预期,但仅有 12% 的 AI 项目实现了全企业范围…

    2026年9月25日 • 用户投稿
    000
  • 京东短信营销的短信管理功能是什么?如何使用?解析京东短信管理功能!

    京东短信营销的短信管理功能是什么?如何使用?解析京东短信管理功能!京东短信营销的短信管理功能是什么?如何使用?解析京东短信管理功能!京东短信营销的短信管理功能是什么?如何使用?解析京东短信管理功能!京东短信营销的短信管理功能是什么?如何使用?解析京东短信管理功能!

    在电商运营中,精准触达用户是提升转化率的关键手段之一。京东短信营销中的短信管理功能,作为连接商家与消费者的高效沟通桥梁,不仅支持活动推广、复购提醒、优惠券发放等多种营销场景,还能通过系统化的规则控制避免对用户造成骚扰。本文将全面剖析该功能的核心优势、操作流程及实用技巧,助力商家掌握低成本、高效益的精…

    2026年9月25日 • 用户投稿
    100
  • 苹果14怎么熄屏

    苹果14怎么熄屏苹果14怎么熄屏苹果14怎么熄屏苹果14怎么熄屏

    熄屏苹果 14 屏幕的方法有:按下电源按钮;从控制中心点击电源图标;按住主屏幕图标下方小圆点向上滑动;使用辅助功能快捷键(音量减小 + 电源按钮);创建快捷指令自动熄屏。如果无法关闭,可尝试:强制重启设备;恢复出厂设置(清除数据)。 苹果 14 如何熄屏 关闭苹果 14 屏幕的方法有以下几种: 物理…

    2026年9月25日 • 用户投稿
    100
  • 本机IP地址获取教程—实用步骤解析本机网络IP检查方式

    本机IP地址获取教程—实用步骤解析本机网络IP检查方式本机IP地址获取教程—实用步骤解析本机网络IP检查方式本机IP地址获取教程—实用步骤解析本机网络IP检查方式本机IP地址获取教程—实用步骤解析本机网络IP检查方式

    通过命令提示符输入ipconfig可查Windows本机IP;2. macOS在系统设置网络选项中查看;3. Linux使用ip a命令查找inet地址;4. 浏览器访问ip.cn等网站可查公网IP。 想知道自己的本机IP地址?无论是排查网络问题,还是设置局域网设备,获取本机IP是基础操作。下面介绍…

    2026年9月25日 • 用户投稿
    400
  • MySQL中unique索引的使用技巧与常见问题解答

    MySQL中unique索引的使用技巧与常见问题解答MySQL中unique索引的使用技巧与常见问题解答MySQL中unique索引的使用技巧与常见问题解答MySQL中unique索引的使用技巧与常见问题解答

    MySQL中unique索引的使用技巧与常见问题解答 MySQL是一种流行的关系型数据库管理系统,在实际应用中,唯一索引(unique index)在数据表设计中起着至关重要的作用。唯一索引能够确保表中某一列的数值唯一,避免出现重复数据。本文将介绍MySQL中unique索引的使用技巧以及一些常见问…

    2026年9月25日 • 用户投稿
    000
  • Bukkit插件开发:正确处理物品显示名称与玩家识别

    Bukkit插件开发:正确处理物品显示名称与玩家识别Bukkit插件开发:正确处理物品显示名称与玩家识别Bukkit插件开发:正确处理物品显示名称与玩家识别Bukkit插件开发:正确处理物品显示名称与玩家识别

    本文旨在解决Bukkit插件开发中,从BlockPlaceEvent获取物品显示名称并将其用于玩家识别时常见的“乱码”问题。我们将深入探讨Component对象与纯文本字符串的区别,并提供两种核心解决方案:直接获取放置方块的玩家名称,以及如何正确地将Component转换为纯文本字符串,以避免不必要…

    2026年9月25日 • 用户投稿
    300
  • 云上书阁app如何绑定手机号_云上书阁app提升账户安全性操作

    云上书阁app如何绑定手机号_云上书阁app提升账户安全性操作云上书阁app如何绑定手机号_云上书阁app提升账户安全性操作云上书阁app如何绑定手机号_云上书阁app提升账户安全性操作云上书阁app如何绑定手机号_云上书阁app提升账户安全性操作

    绑定手机号可提升云上书阁App账户安全性,支持通过“我的”页面或设置菜单操作:进入账号与安全选项,输入手机号并验证短信验证码即可完成绑定。 如果您希望为云上书阁App的账户增加一层保护,绑定手机号是一项关键的安全措施。完成绑定后,您将能更方便地找回密码、接收安全提醒,并提升账户的整体安全性。 本文运…

    2026年9月25日 • 用户投稿
    000
  • sublime怎么折叠所有代码_sublime代码折叠快捷方法

    sublime怎么折叠所有代码_sublime代码折叠快捷方法sublime怎么折叠所有代码_sublime代码折叠快捷方法sublime怎么折叠所有代码_sublime代码折叠快捷方法sublime怎么折叠所有代码_sublime代码折叠快捷方法

    Sublime Text 支持多种代码折叠快捷键,Windows/Linux 使用 Ctrl + Shift + [/] 折叠/展开代码块,Ctrl + K, Ctrl + 1 展开所有用 Ctrl + K, Ctrl + J,macOS 用户将 Ctrl 替换为 Command。 在 Sublim…

    2026年9月25日 • 用户投稿
    200
  • laravel的passport和jwt的区别

    laravel的passport和jwt的区别laravel的passport和jwt的区别laravel的passport和jwt的区别laravel的passport和jwt的区别

    简介 Passport是一个Node.js中间件,它提供了易于实现的各种不同的请求身份验证策略。默认情况下,它将用户对象存储在会话中。    (推荐学习:laravel开发) JSON Web令牌是一种身份验证标准,通过在有助于识别登录用户的请求中分配和传递加密令牌,而不是将用户存储在服务器上的会话…

    2026年9月25日 • 用户投稿
    200

发表回复

登录后才能评论
关注微信