unset()不重排索引是设计使然,因其底层基于哈希表,删除仅标记槽位为空以提升性能;需连续索引时应配合array_values()或改用array_splice()。

unset() 不重排索引是设计使然
unset() 的作用就是「销毁变量或数组元素」,它不负责维护索引连续性。PHP 数组底层是哈希表(HashTable),键(key)和值(value)独立存储,删除某个 $arr[2] 只是把该槽位标记为“空”,并不触发整个结构的重排。这是性能考虑:避免每次删一个元素都遍历重索引。
array_splice() 会重排数字索引,但只对数字键生效
如果你需要删完就自动变成 [0=>'a', 1=>'c'] 这种连续下标,array_splice() 是更直接的选择:
-
array_splice($arr, $offset, 1)删除单个元素,数字索引自动前移 - 它只对「纯数字键且从 0 开始连续」的索引数组才重排;如果原数组是
[1=>'a', 3=>'b'],它不会帮你变成[0=>'a', 1=>'b'] - 注意:
array_splice()是「修改原数组」,且返回被删的片段,不是布尔值
json_encode() 把数组变对象,往往就是索引断了
这是最常被忽略的副作用:json_encode() 判断数组是否为「JSON 数组」的依据,不是「有没有字符串键」,而是「数字键是否从 0 开始、连续、无空缺」。
比如:
立即学习“PHP免费学习笔记(深入)”;
$a = [0 => 'x', 1 => 'y', 2 => 'z'];
unset($a[1]); // → [0=>'x', 2=>'z']
var_dump(json_encode($a)); // string(20) "{"0":"x","2":"z"}" → JSON object!
一旦索引不连续,json_encode() 就按关联数组处理,输出对象而非数组。前端收到 {} 而不是 [],遍历时就容易出错。
重索引不是万能解,得看你要什么
想恢复连续数字下标?array_values($arr) 确实管用,但它会丢掉所有原始键名——包括你本意想保留的语义化键(比如 ['id'=>123, 'name'=>'foo'] 被误用后也会被强制转成 [0=>123, 1=>'foo'])。
所以关键在判断场景:
- 你操作的是纯索引数组(如列表、队列),且后续要
for循环或json_encode→ 删完立刻array_values() - 你操作的是混合结构(比如有数字键也有字符串键),或明确依赖键名含义 → 别用
array_values(),改用array_splice()或手动重建 - 不确定数据来源?加一层校验:
array_keys($arr) === range(0, count($arr)-1)可判断是否为合法索引数组
索引连续性不是 PHP 数组的默认状态,而是你主动选择的结果。别等前端报错才想起查 json_encode 输出了啥。



















