0

0

标题:PHP 递归遍历未知深度的多维 API 数组(避免嵌套 foreach)

花韻仙語

花韻仙語

发布时间:2025-12-26 22:54:03

|

230人浏览过

|

来源于php中文网

原创

标题:PHP 递归遍历未知深度的多维 API 数组(避免嵌套 foreach)

本文介绍一种简洁、可扩展的递归方法,替代传统多层 foreach 循环,高效提取 json api 返回的嵌套数组中同时包含 `value` 和 `id` 的 header 字段及其紧邻的 rows 数据。

当从财务类 API(如 QuickBooks Online 报表接口)获取结构灵活但语义一致的嵌套 JSON 数据时,开发者常面临“深度不可预知”的挑战:Rows → Row → Rows → Row → ... 可能嵌套 3 层、7 层甚至更深,而关键信息(如账户名称 "40000 Sales Income" 及其 ID "31")总出现在某一层的 Header.ColData 中,其对应明细数据则紧随其后位于同级或下级的 Rows.Row.*.ColData 中。

编码多层 foreach 不仅易错、难维护,更无法应对动态报告结构(如“损益表”与“应收账款明细”深度差异大)。真正的解法是递归 + 精准路径守卫(Path Guarding)——即在每一层递归中,只关注当前节点是否满足业务提取条件,而非预设层级。

以下是一个健壮、可复用的递归函数实现:

function extractHeaderWithIdAndChildren(array $data): array {
    $results = [];

    // 安全遍历 Rows.Row(兼容缺失、空或非数组情况)
    $rows = $data['Rows']['Row'] ?? [];
    if (!is_array($rows)) {
        return $results;
    }

    foreach ($rows as $row) {
        // ✅ 条件一:存在 Header.ColData 且至少一个子项含 value + id
        $headerColData = $row['Header']['ColData'] ?? [];
        $hasValidHeader = false;
        $validHeaderItem = null;

        foreach ($headerColData as $col) {
            if (isset($col['value'], $col['id']) && is_string($col['value']) && is_string($col['id'])) {
                $hasValidHeader = true;
                $validHeaderItem = $col;
                break; // 取首个有效项(通常 Header 中仅首列含 id)
            }
        }

        if ($hasValidHeader && $validHeaderItem) {
            // 提取核心标识信息
            $extracted = [
                'value' => $validHeaderItem['value'],
                'id'    => $validHeaderItem['id']
            ];

            // ✅ 条件二:提取“紧邻的后续 ColData”——优先取同级 Rows.Row 下的 ColData(即子行明细)
            // 注意:根据示例结构,目标数据实际在 $row['Rows']['Row'][0]['ColData'](type: "Data")
            $immediateColData = [];
            $nestedRows = $row['Rows']['Row'] ?? [];
            if (is_array($nestedRows) && !empty($nestedRows)) {
                // 遍历子 Row,收集所有 type === "Data" 的 ColData(避免 Summary/Section)
                foreach ($nestedRows as $childRow) {
                    if (isset($childRow['type']) && $childRow['type'] === 'Data' && isset($childRow['ColData'])) {
                        $immediateColData[] = $childRow['ColData'];
                    }
                }
            }

            $results[] = [
                'header' => $extracted,
                'details' => $immediateColData // 多条明细,每条为 ColData 数组
            ];
        } else {
            // ❌ 当前行不匹配 → 递归进入其子结构(如深层嵌套的 Rows.Row)
            // 注意:跳过 Summary/Section 等非数据节点,聚焦 Rows 分支
            if (isset($row['Rows']) && is_array($row['Rows'])) {
                $results = array_merge($results, extractHeaderWithIdAndChildren($row));
            }
        }
    }

    return $results;
}

// 使用示例:
$json = file_get_contents('api_response.json'); // 或来自 cURL 响应
$data = json_decode($json, true);

$extracted = extractHeaderWithIdAndChildren($data);
print_r($extracted);

关键设计说明:

ChatYoutube
ChatYoutube

Youtube视频总结器,一键分析以及对话

下载

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

  • 防御性访问:全程使用 ?? [] 和 isset() 避免 Undefined index,适配 API 字段缺失场景;
  • 语义化判断:不仅检查 value/id 存在,还验证类型(is_string),防止空值或数字 ID 导致逻辑错误;
  • 精准定位明细:不再盲目取 $row['Rows']['Row'][0]['ColData'],而是筛选 type === "Data" 的节点,自动忽略 Summary(报表汇总)和 Section(分组标题);
  • 扁平化结果:无论原始嵌套多深,最终输出统一结构的 ['header' => [...], 'details' => [...]],便于后续导出 CSV 或存入数据库。

⚠️ 注意事项:

  • 若 API 返回极深嵌套(>100 层),需考虑 PHP 默认 xdebug.max_nesting_level 限制,可临时调高或改用式迭代(Stack-based DFS)避免递归栈溢出;
  • 对超大响应(如原文提到的 25KB+),建议配合 json_decode($json, true, 512, JSON_BIGINT_AS_STRING) 防止大整数 ID 被转为科学计数法;
  • 生产环境务必添加日志记录与异常捕获,例如对 json_decode 失败做 json_last_error() 检查。

通过将“结构不确定性”转化为“逻辑确定性”,该方案让代码专注业务意图(找带 ID 的 Header,取它的数据子项),而非纠结于括号嵌套层数——这才是处理动态 API 数据的现代 PHP 实践。

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

1718

2023.09.01

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

1144

2023.10.11

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

1048

2023.10.11

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

948

2023.10.23

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

1396

2023.10.23

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

1228

2023.11.03

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1439

2023.11.09

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1303

2023.11.13

虚拟号码教程汇总
虚拟号码教程汇总

本专题整合了虚拟号码接收验证码相关教程,阅读下面的文章了解更多详细操作。

25

2025.12.25

热门下载

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

精品课程

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

共137课时 | 7.9万人学习

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

共6课时 | 6.9万人学习

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

共13课时 | 0.8万人学习

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

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