
PHP 的 unset() 不会重排数组索引,残留的非连续数字键会使 json_encode() 将其识别为关联数组并编码为 JSON 对象,而非预期的纯数组。使用 array_values() 重置索引即可修复。
php 的 `unset()` 不会重排数组索引,残留的非连续数字键会使 `json_encode()` 将其识别为关联数组并编码为 json 对象,而非预期的纯数组。使用 `array_values()` 重置索引即可修复。
在 PHP 中,unset() 的行为常被误解:它仅删除指定键值对,并不自动重排数组索引,也不会改变数组的“长度”概念。当对数值索引数组(如 [0 => ..., 1 => ...])执行 unset($array[0]); unset($array[1]); 后,原数组实际变为空——但内部键仍保留在内存中(或更准确地说,后续追加时 PHP 会延续最后一个已存在键+1 的逻辑)。此时再通过 $array[] = $value 追加元素,PHP 会从当前最大整型键 + 1 开始分配新索引(例如原键为 0 和 1,删除后最大键为 -1?实际行为是:空数组追加时从 0 开始;但若残留高位键如 [2 => ...],则继续递增),最终导致索引出现断层(如 2, 3)。
而 json_encode() 的序列化规则非常关键:只有当数组键为从 0 开始、连续递增的整数时,才会编码为 JSON 数组 [];一旦键不连续或非从 0 起始,PHP 就将其视为“关联数组”,进而编码为 JSON 对象 {}。这是语言层面的设计,而非 Bug。
以下示例清晰展示了问题与解法:
// 初始数组
$array = [['name' => "pepe"], ['name' => 'marta']];
unset($array[0]);
unset($array[1]); // 此时 $array 实际为 [](空数组),但注意:若之前有更高键,情况不同
$value1 = ['name' => 'mario'];
$value2 = ['name' => 'hector'];
$array[] = $value1; // 自动分配键 0
$array[] = $value2; // 自动分配键 1
echo json_encode($array); // 输出:[{"name":"mario"},{"name":"hector"}] ✅
// 但若此前数组存在高位键(如手动设置过 $array[5]),再 unset 后追加,就会出问题:
$array = [['name' => "pepe"], ['name' => 'marta']];
$array[5] = ['name' => 'temp']; // 引入高位键
unset($array[0]);
unset($array[1]);
$array[] = $value1; // 键变为 6
$array[] = $value2; // 键变为 7
echo json_encode($array); // 输出:{"6":{"name":"mario"},"7":{"name":"hector"}} ❌✅ 正确解决方案:在 json_encode() 前统一调用 array_values(),强制重置为从 0 开始的连续整数索引:
立即学习“PHP免费学习笔记(深入)”;
$array = [['name' => "pepe"], ['name' => 'marta']];
unset($array[0]);
unset($array[1]);
// 模拟高位键残留场景(更典型的问题触发条件)
$array[100] = ['name' => 'legacy']; // 可能来自其他逻辑
unset($array[100]);
$value1 = ['name' => 'mario'];
$value2 = ['name' => 'hector'];
$array[] = $value1;
$array[] = $value2;
// 关键修复步骤:重置索引
$array = array_values($array);
echo json_encode($array);
// 输出:[{"name":"mario"},{"name":"hector"}] ✅⚠️ 注意事项:
- array_values() 返回新数组,原数组不变(需赋值覆盖);
- 若数组中混用字符串键(如 'id' => 123),array_values() 会丢弃所有键名,仅保留值顺序——这对纯数值索引场景是安全的;
- 频繁 unset() + array_values() 可能影响性能(O(n) 时间复杂度),若需高频增删,建议改用 SplFixedArray 或重构为栈/队列逻辑;
- 更健壮的做法是在数据组装阶段避免依赖 unset() 清理,而采用 array_filter() 配合回调函数,再包裹 array_values():
$array = array_values(array_filter($array, function($item) { return !empty($item['name']); // 自定义保留条件 }));
总之,理解 unset() 的语义与 json_encode() 的序列化规则,是写出可预测 JSON 输出的关键。array_values() 是解决索引断裂最直接、最通用的工具。



















