0

0

PHP:将嵌套层级数据结构扁平化为连续数组的实现教程

聖光之護

聖光之護

发布时间:2025-10-23 10:37:18

|

869人浏览过

|

来源于php中文网

原创

PHP:将嵌套层级数据结构扁平化为连续数组的实现教程

本教程详细介绍了如何将php中复杂的嵌套对象或数组(通常用于表示树形结构,如商品分类)转换为一个扁平化的连续数组。通过结合对象到数组的转换函数和递归遍历算法,我们将演示如何高效地提取树形结构中的每个节点数据,并将其组织成一个易于处理的列表,同时移除原始结构中的子节点信息,以满足特定数据处理或展示需求。

在许多Web应用中,我们经常需要处理具有层级关系的数据,例如网站导航菜单、商品分类或组织架构。这些数据通常以嵌套的对象或数组形式存储,其中每个节点可能包含一个 children 属性来指向其子节点。然而,在某些场景下,我们需要将这种树形结构扁平化为一个简单的、不含嵌套的连续数组,以便于列表展示、数据导出或简化后续处理逻辑。

场景描述与需求分析

假设我们有一个 Categories_store_tree 对象,它内部包含一个名为 list_of_sections 的私有属性,该属性存储着一个表示商品分类的树形结构。原始数据结构如下所示:

object(Categories_store_tree)#519 (1) { 
    ["list_of_sections":"Categories_store_tree":private]=> array(5) {                  
        ["id"]=> int(1) 
        ["name"]=> string(11) "Main Store" 
        ["parent_id"]=> NULL 
        ["children"]=> array(2) { 
            [0]=> array(5) { 
                ["id"]=> int(2) 
                ["name"]=> string(4) "Food" 
                ["parent_id"]=> int(1) 
                ["children"]=> array(0) { } 
            } 
            [1]=> array(5) { 
                ["id"]=> int(3) 
                ["name"]=> string(14) "Electronics" 
                ["parent_id"]=> int(1) 
                ["children"]=> array(2) { 
                    [0]=> array(5) { 
                        ["id"]=> int(4) 
                        ["name"]=> string(8) "Headphones" 
                        ["parent_id"]=> int(3) 
                        ["children"]=> array(0) { } 
                    } 
                    [1]=> array(5) { 
                        ["id"]=> int(5) 
                        ["name"]=> string(5) "Smartphones" 
                        ["parent_id"]=> int(3) 
                        ["children"]=> array(0) { } 
                    } 
                } 
            } 
        } 
    } 
} 

我们的目标是将其转换为一个扁平化的数组结构,其中每个元素代表一个分类,且不包含 children 属性,如下所示:

object(Categories_store_tree)#964 (1) { 
    ["list_of_sections":"Categories_store_tree":private]=> array(5) { 
        [0]=> array(4) { 
            ["id"]=> int(1) 
            ["name"]=> string(11) "Main Store" 
            ["parent_id"]=> NULL 
        } 
        [1]=> array(4) { 
            ["id"]=> int(2) 
            ["name"]=> string(4) "Food" 
            ["parent_id"]=> int(1) 
        } 
        [2]=> array(4) { 
            ["id"]=> int(3) 
            ["name"]=> string(14) "Electronics" 
            ["parent_id"]=> int(1) 
        } 
        [3]=> array(4) { 
            ["id"]=> int(4) 
            ["name"]=> string(8) "Headphones" 
            ["parent_id"]=> int(3) 
        } 
        [4]=> array(4) { 
            ["id"]=> int(5) 马
            ["name"]=> string(5) "Smartphones" 
            ["parent_id"]=> int(3) 
        } 
    } 
}

注意,目标结构中 list_of_sections 的值现在是一个索引数组,包含了所有分类的扁平列表。

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

实现步骤与代码示例

为了实现上述转换,我们需要两个主要步骤:

Skybox AI
Skybox AI

一键将涂鸦转为360°无缝环境贴图的AI神器

下载
  1. 将初始对象转换为多维数组:这有助于我们统一数据结构,便于后续处理。
  2. 递归遍历并扁平化数组:这是核心步骤,通过递归函数遍历树形结构,提取每个节点的关键信息,并将其添加到扁平化列表中。

1. 对象到数组的转换

如果您的原始数据是一个PHP对象,首先需要将其转换为一个多维数组。这可以通过一个通用的递归函数实现。

list_of_sections = $data;
    }
}

$initialData = [
    "id" => 1,
    "name" => "Main Store",
    "parent_id" => NULL,
    "children" => [
        [
            "id" => 2,
            "name" => "Food",
            "parent_id" => 1,
            "children" => []
        ],
        [
            "id" => 3,
            "name" => "Electronics",
            "parent_id" => 1,
            "children" => [
                [
                    "id" => 4,
                    "name" => "Headphones",
                    "parent_id" => 3,
                    "children" => []
                ],
                [
                    "id" => 5,
                    "name" => "Smartphones",
                    "parent_id" => 3,
                    "children" => []
                ]
            ]
        ]
    ]
];

$originalObject = new Categories_store_tree($initialData);

// 将对象转换为数组
$convertedArray = objectToArray($originalObject);

echo "--- 转换后的原始数组结构 ---" . PHP_EOL;
print_r($convertedArray);
echo PHP_EOL;

经过 objectToArray 函数处理后,$convertedArray 将是一个纯粹的PHP数组,其结构与原始对象的内部结构保持一致,只是不再是对象形式。

2. 递归遍历与扁平化

接下来,我们需要编写一个递归函数来遍历这个多维数组。这个函数将访问每个节点,提取我们需要的 id, name, parent_id 属性,并将其添加到一个新的扁平化列表中。

 $node['id'],
        'name' => $node['name'],
        'parent_id' => $node['parent_id']
    ];
    $flatList[] = $currentCategory; // 将当前分类添加到扁平化列表

    // 检查是否存在子节点,如果存在且为非空数组,则递归处理
    if (isset($node['children']) && is_array($node['children']) && !empty($node['children'])) {
        foreach ($node['children'] as $childNode) {
            flattenCategoryTree($childNode, $flatList);
        }
    }
}

// 初始化一个空数组来存储扁平化后的分类列表
$flatCategories = [];

// 假设 $convertedArray['list_of_sections'] 是我们分类树的根节点
// 确保 'list_of_sections' 存在且是一个数组
if (isset($convertedArray['list_of_sections']) && is_array($convertedArray['list_of_sections'])) {
    flattenCategoryTree($convertedArray['list_of_sections'], $flatCategories);
}

echo "--- 扁平化后的分类列表 ---" . PHP_EOL;
print_r($flatCategories);
echo PHP_EOL;

// 如果需要将其重新封装到 Categories_store_tree 对象中(如示例输出所示)
// 尽管通常扁平化后就不需要再封装回原对象,但为了匹配示例,可以这样做
$finalObject = new Categories_store_tree($flatCategories);
echo "--- 重新封装到对象后的结构 (与目标输出格式匹配) ---" . PHP_EOL;
print_r($finalObject);
echo PHP_EOL;

?>

完整代码示例

将上述两个部分整合,形成一个完整的解决方案:

 $node['id'],
        'name' => $node['name'],
        'parent_id' => $node['parent_id']
    ];
    $flatList[] = $currentCategory; // 将当前分类添加到扁平化列表

    // 检查是否存在子节点,如果存在且为非空数组,则递归处理
    if (isset($node['children']) && is_array($node['children']) && !empty($node['children'])) {
        foreach ($node['children'] as $childNode) {
            flattenCategoryTree($childNode, $flatList);
        }
    }
}

// 模拟 Categories_store_tree 类和其数据
class Categories_store_tree {
    // 在实际应用中,如果 list_of_sections 是 private,
    // objectToArray 可能需要特殊处理或通过反射才能访问。
    // 为了简化和匹配 var_dump 行为,这里将其设为 public 或提供访问器。
    // 在本例中,我们直接模拟一个可访问的结构。
    public $list_of_sections;

    public function __construct($data) {
        $this->list_of_sections = $data;
    }
}

// 原始嵌套数据结构
$initialNestedData = [
    "id" => 1,
    "name" => "Main Store",
    "parent_id" => NULL,
    "children" => [
        [
            "id" => 2,
            "name" => "Food",
            "parent_id" => 1,
            "children" => []
        ],
        [
            "id" => 3,
            "name" => "Electronics",
            "parent_id" => 1,
            "children" => [
                [
                    "id" => 4,
                    "name" => "Headphones",
                    "parent_id" => 3,
                    "children" => []
                ],
                [
                    "id" => 5,
                    "name" => "Smartphones",
                    "parent_id" => 3,
                    "children" => []
                ]
            ]
        ]
    ]
];

// 实例化模拟的 Categories_store_tree 对象
$originalObject = new Categories_store_tree($initialNestedData);

echo "--- 原始对象结构 (模拟) ---" . PHP_EOL;
var_dump($originalObject);
echo PHP_EOL;

// 1. 将对象转换为数组
// 注意:如果 `list_of_sections` 是 private,直接 `(array) $originalObject` 会导致键名变化
// 更好的做法是:
$convertedArray = ['list_of_sections' => objectToArray($originalObject->list_of_sections)];
// 或者如果 objectToArray 能处理私有属性,直接 $convertedArray = objectToArray($originalObject);
// 这里我们假设 objectToArray 能够正确处理,或者我们直接从对象中取出需要处理的部分。
// 鉴于原始问题给出的 objectToArray 函数,它通常用于 stdClass 或公共属性。
// 对于 private 属性,更准确的做法是:
$reflectionClass = new ReflectionClass($originalObject);
$property = $reflectionClass->getProperty('list_of_sections');
$property->setAccessible(true); // 使私有属性可访问
$convertedArrayRoot = $property->getValue($originalObject);
$convertedArray = ['list_of_sections' => objectToArray($convertedArrayRoot)]; // 再次确保子结构也被转换

echo "--- 转换后的中间数组结构 ---" . PHP_EOL;
print_r($convertedArray);
echo PHP_EOL;

// 2. 初始化一个空数组来存储扁平化后的分类列表
$flatCategories = [];

// 确保 'list_of_sections' 存在且是一个数组,然后开始扁平化
if (isset($convertedArray['list_of_sections']) && is_array($convertedArray['list_of_sections'])) {
    flattenCategoryTree($convertedArray['list_of_sections'], $flatCategories);
}

echo "--- 扁平化后的分类列表 ---" . PHP_EOL;
print_r($flatCategories);
echo PHP_EOL;

// 如果需要将扁平化结果重新封装到 Categories_store_tree 对象中,以匹配目标输出格式
$finalObject = new Categories_store_tree($flatCategories);

echo "--- 重新封装到 Categories_store_tree 对象后的结构 ---" . PHP_EOL;
var_dump($finalObject);
echo PHP_EOL;

?>

注意事项与总结

  1. 对象属性访问: 如果 Categories_store_tree 类中的 list_of_sections 属性是 private 或 protected,直接使用 get_object_vars() 或 (array) 强制类型转换可能无法直接访问到它,或者会导致键名发生变化(如 \0Categories_store_tree\0list_of_sections)。在实际应用中,您可能需要:
    • 在 Categories_store_tree 类中提供一个公共的 getter 方法来获取 list_of_sections。
    • 使用 PHP 的反射(ReflectionClass)API 来访问私有或保护属性,如完整代码示例中所示。
  2. 数据结构一致性: 确保您的 children 键名在整个树结构中保持一致。如果存在其他名称的子节点键,您需要调整 flattenCategoryTree 函数中的 isset($node['children']) 条件。
  3. 性能考虑: 对于非常深的树结构或包含大量节点的树,递归函数可能会消耗较多的内存(因为每次递归调用都会增加调用深度)。在极端情况下,可能会遇到栈溢出错误。对于此类情况,可以考虑使用迭代方式(例如,使用栈或队列)来实现扁平化,但这会增加代码的复杂性。
  4. 错误处理: 在实际生产环境中,您可能需要添加更多的错误检查,例如 id、name、parent_id 键是否存在,以防止因数据不完整而导致的运行时错误。

通过上述方法,您可以有效地将复杂的嵌套树形数据结构转换为扁平化的列表,这在许多数据展示和处理场景中都

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java进行强制类型转换
java进行强制类型转换

强制类型转换是Java中的一种重要机制,用于将一个数据类型转换为另一个数据类型。想了解更多强制类型转换的相关内容,可以阅读本专题下面的文章。

286

2023.12.01

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

539

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

21

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

28

2026.01.06

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

397

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

575

2023.08.10

C++类型转换方式
C++类型转换方式

本专题整合了C++类型转换相关内容,想了解更多相关内容,请阅读专题下面的文章。

301

2025.07.15

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

411

2023.08.14

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

0

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 10.2万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.2万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号