PHP索引数组的[]赋值不自动递增到逻辑末尾,而是取当前最大非负整数键+1;字符串键、负数键及空缺均被忽略,需用array_values()重索引确保连续。

PHP索引数组下标默认从0开始,但不会“自动递增”到已有键之后
很多人以为 array[] = $value 总是追加到最大数字键+1,其实不然——PHP只在**所有键都是非负整数且连续或接近连续**时才按预期递增。一旦数组里混入字符串键、负数键、或跳过某些整数(比如删掉中间元素),[] 就会从当前最大**非负整数键** + 1 开始,而不是逻辑上“下一个位置”。
常见错误现象:
- 执行 unset($arr[1]) 后再 $arr[] = 'new',新元素下标不是 1,而是 count($arr)(即原长度),导致跳号;
- 混用 $arr['name'] = 'x' 和 $arr[] = 'y',后者仍基于数字键最大值,和字符串键完全无关。
实操建议:
- 不依赖 [] 的“自动性”,需要严格顺序时显式用 array_push() 或 array[] = $value 前先 array_values() 重排;
- 判断是否为纯索引数组:用 array_keys($arr) === range(0, count($arr)-1);
- 避免手动 unset 后直接追加,改用 array_splice($arr, $offset, 1) 或重索引。
array[] = $value 的实际递增规则取决于 array_keys() 中的最大非负整数
PHP 内部维护一个“下一个数字索引”(next numeric index),它只看 array_keys($arr) 里所有 >= 0 的整数,取其中最大值 + 1。其余键(字符串、负数、浮点数)全被忽略。
示例对比:$a = [0 => 'a', 2 => 'c']; $a[] = 'd'; // $a[3] = 'd',因为 max int key 是 2$b = [-1 => 'x', 'k' => 'y']; $b[] = 'z'; // $b[0] = 'z',因为没有 >=0 的整数键$c = [0 => 'a', '1' => 'b']; $c[] = 'c'; // $c[2] = 'c',因为 '1' 是字符串键,不参与计算
关键点:
- 字符串数字键(如 '1')≠ 整数键,不会被 [] 认作索引;
- 负数键(如 -5)不影响 next index;
- array_merge() 会重置数字键,而 + 运算符保留原键——这点常被忽略,导致追加行为突变。
用 array_values() 强制重索引是最安全的“自动递增”方案
当你要确保新元素总在末尾且下标连续,唯一可靠方式是先重排键名。PHP 不提供“智能追加”,array_values() 是最轻量、兼容性最好的兜底手段。
立即学习“PHP免费学习笔记(深入)”;
使用场景:
- 用户动态删除某几项后继续添加;
- 合并多个来源数组,需统一为标准索引;
- JSON 输出前避免键名跳跃(虽然 JSON 不关心键序,但前端解析习惯依赖连续数字键)。
实操建议:
- $arr = array_values($arr); $arr[] = $new; ——两步明确,无歧义;
- 如果性能敏感且确定没删过元素,可跳过 array_values(),但别假设“肯定连续”;
- 不要用 for ($i = 0; $i 遍历时顺手 $arr[] = ...,循环中修改数组长度易出错。
json_encode() 和 foreach 对稀疏索引数组的处理差异容易引发 bug
PHP 数组本质是有序哈希表,foreach 按插入顺序遍历,不管键是否连续;但 json_encode() 遇到非连续数字键会强制转成对象(而非 JSON 数组),这是最隐蔽的坑。
示例:$x = [0 => 'a', 2 => 'c']; json_encode($x); // {"0":"a","2":"c"} → JS 里是 object,不是 array$y = array_values($x); json_encode($y); // ["a","c"] → 正确 JSON 数组
所以,只要数组可能输出为 JSON,就必须检查是否稀疏:
- 用 array_keys($arr) !== range(0, count($arr)-1) 判断;
- 或直接 json_encode(array_values($arr)) 省心;
- 不要依赖 is_array(json_decode($json)) 的返回值,PHP 7.4+ 的 json_decode($json, true) 对非连续键也返回关联数组,前端无法用 arr.push()。











