如何在 PHP 中正确遍历数据库结果并构建包含地理编码位置的多维数组

本文讲解如何将 pdo 查询返回的多条记录逐条处理,为每条记录调用反向地理编码接口生成 location 字段,并保持完整数组结构返回,避免因变量覆盖导致仅返回单条数据的问题。

在使用 PDO::FETCH_NAMED 获取数据库结果后,$stmt->fetchAll() 返回的是一个索引数组,每个元素是一条关联记录(即多维数组)。若想对每条记录进行加工(如调用 reverse_geocode() 将坐标转为地址),必须确保处理结果仍以数组形式逐条追加,而非反复赋值给同一变量——否则后续循环会不断覆盖前次结果,最终只保留最后一条。

正确的做法是:初始化一个空数组 $result = [],并在 foreach 循环中使用 $result[] = [...] 语法将每条转换后的记录推入数组末尾。这样既保留了原始记录数量,又支持新增字段(如 location)和结构重组(如拆分 name 数组为 nameA/nameB/nameC)。

以下是推荐实现代码:

$matches = $stmt->fetchAll(PDO::FETCH_NAMED);
$result = []; // 显式初始化空数组,提高可读性与健壮性

foreach ($matches as $match) {
    // 安全访问 name 数组,防止索引越界(生产环境建议增加判断)
    $nameA = $match['name'][0] ?? '';
    $nameB = $match['name'][1] ?? '';
    $nameC = $match['name'][2] ?? '';

    // 调用地理编码服务获取位置名称(注意:实际项目中应异步或批量处理以提升性能)
    $location = $this->reverse_geocode(
        trim($match['coordinate x'] ?? ''),
        trim($match['coordinate y'] ?? '')
    );

    // 构建新记录并追加到结果数组
    $result[] = [
        'nameA'      => $nameA,
        'nameB'      => $nameB,
        'nameC'      => $nameC,
        'date'       => $match['date'],
        'round'      => $match['round'],
        'leauge_id'  => $match['leauge_id'],
        'location'   => $location ?: 'Unknown location',
    ];
}

return $result;

⚠️ 关键注意事项:

  • 不要直接写 $result = [...]:这会把 $result 变成单个关联数组,丢失所有历史记录;
  • 务必使用 $result[] = [...]:PHP 自动递增索引,确保返回标准 JSON 数组格式(前端 fetch().then(res => Array.isArray(res)) 返回 true);
  • 坐标字段需清洗:coordinate x 和 coordinate y 含空格,调用前建议 trim();
  • 异常防护:reverse_geocode() 可能失败或超时,建议添加 try-catch 或默认值兜底(如示例中的 'Unknown location');
  • 性能优化提示:若记录量大(如 >50 条),频繁调用 Google Geocoding API 可能触发配额限制或显著拖慢响应。此时应改用批量地理编码(如预存坐标 → 地址映射表)或前端 JS SDK 异步加载位置,后端仅传递原始坐标。

最终返回的 JSON 将是符合预期的数组格式:

[
  {
    "nameA": " name1",
    "nameB": " name2",
    "nameC": " name3",
    "date": "2025-02-05 12:00:00",
    "round": "3",
    "leauge_id": 4,
    "location": "Berlin, Germany"
  },
  { ... }
]

前端可直接遍历渲染,无需额外解析逻辑。