




本文详解如何安全、准确地遍历由 json_decode($json, true) 生成的深层嵌套数组,并在 html 表格中逐条渲染物流扫描记录,避免“undefined array key”和“foreach on null”等常见错

在 PHP 中处理 API 返回的 JSON 数据时,使用 json_decode($json, true) 将其转为关联数组是常规做法。但当结构深度较大(如物流追踪数据中包含 ShipmentData → Shipment → Scans → [n] → ScanDetail)时,直接链式访问(如 $item['Shipment']['Scans']['ScanDetail'])极易因键不存在或类型不匹配而触发警告甚至致命错误——正如问题中所示:Warning: Undefined array key "Shipment" 和 foreach() argument must be of type array|object, null given。
根本原因在于:$item['Shipment']['Scans'] 是一个索引数组(含多个 [0] => [...], [1] => [...] 元素),而每个元素内部才是 ['ScanDetail'] 关联子数组。因此,$item['Shipment']['Scans']['ScanDetail'] 实际试图访问一个不存在的字符串键 'ScanDetail'(而非遍历数组),导致返回 null,后续 foreach 即报错。
✅ 正确做法是逐层判断 + 安全遍历。以下是推荐的健壮实现:
$json = file_get_contents('https://track.delhivery.com/api/v1/packages/json/?waybill=&token=');
$arr = json_decode($json, true);
// 【关键】添加基础结构校验,防止空响应或格式异常
if (!is_array($arr) || !isset($arr['ShipmentData']) || empty($arr['ShipmentData'])) {
echo '未获取到有效物流数据,请检查运单号或 Token。
';
exit;
}
$items = $arr['ShipmentData'];
echo '';
echo '扫描时间 操作状态 扫描地点 状态码 ';
echo '';
foreach ($items as $item) {
// 确保 Shipment 存在且为数组
if (!isset($item['Shipment']) || !is_array($item['Shipment'])) continue;
$shipment = $item['Shipment'];
// 确保 Scans 存在且为非空数组
if (!isset($shipment['Scans']) || !is_array($shipment['Scans']) || empty($shipment['Scans'])) continue;
// 第一层:遍历 Scans 数组(每个元素是一个含 'ScanDetail' 的子数组)
foreach ($shipment['Scans'] as $scan) {
// 确保当前 scan 元素包含 'ScanDetail' 且为数组
if (!isset($scan['ScanDetail']) || !is_array($scan['ScanDetail'])) continue;
$detail = $scan['ScanDetail'];
// 输出单条扫描记录
echo '';
echo '' . htmlspecialchars($detail['ScanDateTime'] ?? 'N/A') . ' ';
echo '' . htmlspecialchars($detail['Scan'] ?? 'N/A') . ' ';
echo '' . htmlspecialchars($detail['ScannedLocation'] ?? 'N/A') . ' ';
echo '' . htmlspecialchars($detail['StatusCode'] ?? 'N/A') . ' ';
echo ' ';
}
}
echo '
'; ? 关键注意事项:
通过以上方式,你不仅能解决原始报错,还能构建出稳定、可维护、具备容错能力的 JSON 数据渲染逻辑,适用于各类物流、订单、报表等多维 API 响应场景。