
本文详解如何在 php 中安全、准确地遍历 json 解码后的深层嵌套数组(如 delhivery 物流 api 返回的 shipmentdata),避免“undefined array key”和“foreach on null”等常见错误,并生成结构化 html 表格。
在使用 json_decode($json, true) 将 JSON 响应转为 PHP 关联数组后,开发者常因忽略数组层级结构而触发运行时警告——例如本文中的错误:Warning: Undefined array key "Shipment" 和 foreach() argument must be of type array|object, null given。根本原因在于:$item['Shipment']['Scans'] 本身是一个索引数组(含多个 [0] => [...], [1] => [...] 元素),而 ['ScanDetail'] 并非其直接子键,而是每个扫描项内部的键名。原代码错误地将 Scans 视为一个扁平对象,试图用 $item['Shipment']['Scans']['ScanDetail'] 直接访问,导致 PHP 在 Scans 数组上执行非法键查找,最终返回 null,进而使内层 foreach 失败。
✅ 正确做法是逐层解构嵌套结构。以 Delhivery API 的典型响应为例,完整路径为:
$arr['ShipmentData'][0]['Shipment']['Scans'][i]['ScanDetail'][...]
其中 Scans 是一个数字索引数组,每个元素(如 [0], [1])都是一个包含 'ScanDetail' 键的关联数组。
以下是健壮、可落地的解决方案(含空值防护与语义化结构):
&token='); $arr = json_decode($json, true); // 【关键】添加基础校验,防止空响应或结构异常 if (empty($arr) || !isset($arr['ShipmentData']) || !is_array($arr['ShipmentData'])) { echo ' ⚠️ 未获取到有效物流数据,请检查运单号或 Token 是否正确。
'; exit; } $shipments = $arr['ShipmentData']; echo ''; echo '
'; ?>'; echo ''; foreach ($shipments as $shipment) { // 确保 Shipment 存在且为数组 if (!isset($shipment['Shipment']) || !is_array($shipment['Shipment'])) continue; $shipmentData = $shipment['Shipment']; // 确保 Scans 存在且为数组(注意:Scans 是数组,不是对象!) if (!isset($shipmentData['Scans']) || !is_array($shipmentData['Scans'])) continue; // 第一层:遍历 Scans 数组([0], [1], [2]...) foreach ($shipmentData['Scans'] as $scanItem) { // 每个 scanItem 应为 ['ScanDetail' => [...]] 结构 if (!isset($scanItem['ScanDetail']) || !is_array($scanItem['ScanDetail'])) continue; $detail = $scanItem['ScanDetail']; // 输出表格行:安全提取字段,缺失则设为空字符串 echo ' 扫描时间 操作类型 状态说明 位置 '; echo ' '; } } echo '' . htmlspecialchars($detail['ScanDateTime'] ?? '') . ' '; echo '' . htmlspecialchars($detail['ScanType'] ?? '') . ' '; echo '' . htmlspecialchars($detail['Instructions'] ?? '') . ' '; echo '' . htmlspecialchars($detail['ScannedLocation'] ?? '') . ' '; echo '
? 关键注意事项:
立即学习“PHP免费学习笔记(深入)”;
- 永远不要跳过存在性检查:使用 isset() + is_array() 双重验证每一级键(尤其是 Shipment、Scans、ScanDetail),这是避免 Undefined array key 的黄金法则;
- 理解数据结构本质:Scans 是数值索引数组([0], [1], ...),而非关联对象,因此必须用 foreach ($scans as $scanItem) 而非 $scans['ScanDetail'];
- 防御式输出:使用 ?? '' 提供默认值,并通过 htmlspecialchars() 防止 XSS;
- 调试技巧:开发阶段可用 var_dump(array_keys($shipmentData)) 或 print_r(array_slice($shipmentData['Scans'], 0, 1)) 快速确认实际键名与结构;
- API 响应容错:真实场景中,Scans 可能为空数组或完全缺失,上述代码已内置兼容逻辑。
通过严格遵循“先验证、再访问、最后渲染”的三层原则,即可稳定解析任意深度的物流、订单或报表类 JSON 数据,并生成清晰、安全的 HTML 表格。











