
php 数组在用 unset() 删除元素后会保留原键名,导致键不连续;json_encode() 检测到非连续数字索引时自动转为关联对象,而非预期的 json 数组。解决方法是用 array_values() 重置索引。
php 数组在用 unset() 删除元素后会保留原键名,导致键不连续;json_encode() 检测到非连续数字索引时自动转为关联对象,而非预期的 json 数组。解决方法是用 array_values() 重置索引。
在 PHP 中,unset() 并不会“压缩”数组,它只是移除指定键值对,而原有键名(如 0、1)被删除后,剩余或后续追加的元素仍沿用原始索引逻辑。例如:
$array = [['name' => "pepe"], ['name' => 'marta']];
unset($array[0]);
unset($array[1]);
// 此时 $array 实际为空数组,但内部键已“空缺”
var_dump($array); // array(0) {}
$array[] = ['name' => 'mario'];
$array[] = ['name' => 'hector'];
var_dump($array);
// 输出:
// array(2) {
// [2] => array(1) { ["name"] => string(5) "mario" }
// [3] => array(1) { ["name"] => string(6) "hector" }
// }
由于 PHP 数组本质是有序哈希表,$array[] 追加操作会从当前最大整型键 + 1 开始分配新键(此处原数组最大键为 1,已被 unset,但内部计数器仍延续),因此新元素被赋予键 2 和 3 —— 键不再从 0 开始且不连续。
而 json_encode() 的行为规范明确:仅当数组键为从 0 开始的连续整数时,才编码为 JSON 数组 [];否则一律视为关联数组(即 JSON 对象 {})。这就是为何输出为:
{"2":{"name":"mario"},"3":{"name":"hector"}}
而非期望的:
[{"name":"mario"},{"name":"hector"}]
✅ 正确做法:在 json_encode() 前调用 array_values() 强制重索引:
$array = [['name' => "pepe"], ['name' => 'marta']];
unset($array[0]);
unset($array[1]);
$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() 会丢弃键名、仅保留值,适用于纯索引场景;
- 替代方案包括使用 array_filter()(默认去除空值并保留键)+ array_values() 组合,或改用 array_splice() 等更安全的删除方式;
- 在循环中频繁 unset() 后追加,建议统一在最后执行一次 array_values(),避免重复重索引开销。
总结:PHP 数组的“稀疏性”是语言特性而非 bug,json_encode() 的序列化规则严格遵循 JSON 规范。理解索引机制 + 主动重置键名,是确保 API 输出符合前端预期的关键实践。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











