根本原因是合并后数组键不连续或不从0开始,导致json_encode将其视为关联数组而输出{};array_merge会重排数字键,但若输入含字符串键、非连续数字键或非零起始键,则破坏连续性。

PHP 中用 array_merge 合并数组后,json_encode 把数字键数组变成对象(即输出 {} 而非 []),根本原因是:合并后的数组**键不再连续或不从 0 开始**,导致 PHP 认为它不是“纯索引数组”,而 json_encode 默认只对“连续数字索引且从 0 开始”的数组才编码为 JSON 数组([]);否则视为关联数组,编码为 JSON 对象({})。
为什么 array_merge 会破坏索引连续性?
array_merge 会**重排数字键**:它把所有数字键丢弃,重新按顺序从 0 开始分配索引。但前提是输入数组本身是「纯数字索引」。如果其中任意一个数组含有字符串键、或数字键不连续(比如 [2 => 'a', 5 => 'b']),或合并前已有非零起始键(如 [1 => 'x']),合并后就大概率产生“非连续”或“缺失 0 键”的情况,从而被 json_encode 当作关联数组处理。
例如:
↓ 这样合并后,键变成 0,1,2 —— 连续且从 0 开始 → json_encode 输出 []$a = [1, 2]; $b = [3, 4]; $merged = array_merge($a, $b); // [0=>1, 1=>2, 2=>3, 3=>4]
立即学习“PHP免费学习笔记(深入)”;
$a = [1, 2]; $b = [3 => 'x']; $merged = array_merge($a, $b); // [0=>1, 1=>2, 2=>'x'] ❌ 实际是 [0=>1, 1=>2, 3=>'x'] → 键不连续
如何判断数组是否会被 json_encode 当作对象?
用这个函数快速检测:
function isSequentialArray($arr) {
if (!is_array($arr)) return false;
$keys = array_keys($arr);
return $keys === array_keys($keys); // 等价于:键是 0,1,2,... 连续整数
}
或者更直接地,在 json_encode 前加个类型强制:
-
想确保输出 JSON 数组([]):用
array_values($arr)重置键为连续数字索引 -
想确保输出 JSON 对象({}):显式传入
JSON_FORCE_OBJECT选项
推荐的修复方式(保持语义正确)
根据你的业务意图选择:
-
你本意就是处理“列表”(如用户列表、订单列表) → 合并后立刻调用
array_values():$result = json_encode(array_values(array_merge($a, $b))); -
你合并的是带含义的键(如
['id'=>1, 'name'=>'A']) → 不该期望输出[],此时{}是正确行为;若强行转成数组反而丢失结构 -
不确定数据结构,但前端必须接收数组 → 统一用
array_values()+ 显式检查是否为空:$safeArr = array_values($merged); echo json_encode($safeArr);
其他容易踩坑的操作
-
+运算符合并数组不会重排数字键,但会保留原键 → 可能保留[1=>'a', 3=>'b'],依然不被识别为索引数组 -
array_merge_recursive同样会重排数字键,问题相同 -
json_encode($arr, JSON_FORCE_OBJECT)强制输出对象,适合需要固定结构的 API 响应



















