
本文介绍如何从数据库查询返回的对象数组中,按国家(country)分组并构建层级化结构:先提取唯一国家,再为每个国家聚合其下属省份及对应城市,保持原始数据关系。
在实际开发中,我们常遇到类似场景:数据库返回扁平化的结果集(如多条记录代表不同城市),但前端或业务逻辑需要按地理层级(国家 → 省份 → 城市)组织数据。关键在于不是简单地对各字段单独去重,而是要保留字段间的语义关联——即“Toronto 属于 Ontario,Ontario 属于 Canada”。
最简洁、高效且可读性强的实现方式是使用 PHP 的多维关联数组进行原生分组。核心思路是:以 country 为第一级键,province 为第二级键,city 为第三级键,将每条记录存入对应路径下(也可仅存储必要字段,避免冗余)。
以下是完整示例代码:
// 假设 $db_data 是你的数据库查询结果(对象数组)
$result = [];
foreach ($db_data as $item) {
$country = $item->country;
$province = $item->province;
$city = $item->city;
// 自动创建嵌套结构:$result[country][province][city] = $item
$result[$country][$province][$city] = $item;
}
// 输出结构化数据(可用于模板渲染或 API 返回)
print_r($result);该方案优势明显:
- ✅ 零依赖:纯 PHP 原生语法,无需额外函数或扩展;
- ✅ 保持关系:每个城市节点仍可访问其完整原始对象(含 living_cost 等字段);
- ✅ 天然去重:因使用字符串键($country, $province, $city),重复组合自动覆盖,等效于“按三字段联合去重”;
- ✅ 灵活扩展:若需统计每省城市数,可直接用 count($result[$country][$province])。
⚠️ 注意事项:
- 确保 $item->country、$item->province、$item->city 值不为 null 或空字符串,否则可能导致意外键名(如 '')。建议在循环内添加过滤:
if (empty($country) || empty($province) || empty($city)) continue;
- 若只需城市名称列表(而非完整对象),可简化为:
$result[$country][$province][] = $city; - 如需排序(如国家/省份按字母序),可在构建完成后使用 ksort($result) 及嵌套 ksort() 处理。
最终,你将获得一个清晰、可遍历的三层嵌套数组,可直接用于生成 HTML 列表、JSON API 响应,或进一步转换为树形结构。










