Skip to content

[L1] PHP 索引数组与关联数组的区别及常见操作

一句话结论

PHP 数组统一用有序哈希表实现,索引数组与关联数组只是键的写法不同,底层结构完全一致。

体系讲解

原理:PHP 的数组不是"数组"

传统语言中的数组(如 C 的 int arr[])是一段连续内存,以整数下标做偏移访问。PHP 的数组本质是有序字典(ordered map),同时支持整数键和字符串键,且保持插入顺序。

  • 索引数组:键为从 0 开始的连续整数,写法类似传统数组。
  • 关联数组:键为字符串,写法类似字典 / map。

两者可以混用,PHP 不做区分——它们是同一数据结构的不同使用方式。

机制:键的自动转换规则

PHP 在赋值时会对键做隐式类型转换:

  1. 合法整数形式的字符串键(如 "1")自动转为整数键。
  2. 浮点数键截断为整数($a[1.7] 等同于 $a[1])。
  3. true 转为 1false 转为 0null 转为 ""
  4. 未指定键时,取当前最大整数键 + 1。

常用数组函数速查

场景函数说明
判断键是否存在array_key_exists()区分"不存在"和"值为 null"
判断值是否存在in_array($v, $arr, true)第三参数 true 启用严格比较
合并数组array_merge()字符串键覆盖,整数键重新编号
合并保留键+ 运算符键冲突时保留左侧,不重新编号
遍历foreach ($arr as $k => $v)按插入顺序遍历
排序sort() / asort() / ksort()注意是否保留键名

结论:对开发的直接影响

  • 不需要像其他语言那样在数组和字典之间做选型,PHP 数组"一招通吃"。
  • 但也因此容易踩隐式转换的坑:"0"0 是同一个键,true1 也是。
  • array_merge()+ 的行为差异是高频面试陷阱,必须区分清楚。

考察意图

  • 验证候选人是否理解 PHP 数组的本质是有序字典,而非简单的线性结构
  • 考察对键的隐式转换规则的了解,这是日常开发中隐蔽 bug 的来源
  • 检验对 array_merge()+ 等常用函数行为差异的掌握

追问链

  1. array_merge()+ 运算符合并数组时有什么区别?

    简答:array_merge() 遇到字符串键后者覆盖前者,整数键全部保留并重新从 0 编号。+ 运算符遇到任何重复键都保留左侧(先出现的),整数键不重新编号。

  2. $arr = ["1" => "a", 1 => "b"]$arr 最终有几个元素?

    简答:只有 1 个。字符串 "1" 会被转为整数键 1,后面的赋值覆盖前面的,最终 $arr = [1 => "b"]

  3. sort()asort() 有什么区别?什么时候该用哪个?

    简答:sort() 对值排序并重置键为 0, 1, 2...,适合索引数组。asort() 对值排序但保留原始键名,适合关联数组需要保持键值对应关系的场景。

  4. 如何判断一个数组是索引数组还是关联数组?

    简答:PHP 没有内置函数区分。常用判断方式是 array_is_list()(PHP 8.1+),它检测数组键是否为从 0 开始的连续整数。PHP 8.1 之前可用 $arr === array_values($arr) 近似判断。

易错点

  1. 以为 array_merge()+ 效果一样:二者对整数键的处理截然不同。array_merge([0 => 'a'], [0 => 'b']) 得到 ['a', 'b'](两个元素,重新编号),而 [0 => 'a'] + [0 => 'b'] 得到 ['a'](左侧优先,只有一个元素)。

  2. 忽略键的隐式转换$arr["0"]$arr[0] 指向同一个元素。在从数据库取数据(字段值通常是字符串)后用整数做键查找,或反过来,都可能产生意外覆盖。

  3. 以为 foreach 遍历顺序不确定:有其他语言经验的候选人(如 Go 的 map 遍历顺序随机)常做此假设。PHP 数组始终按插入顺序遍历,这是语言规范保证的。

代码示例

php
<?php

// 索引数组与关联数组的声明
$indexed = ['apple', 'banana', 'cherry'];        // 键: 0, 1, 2
$assoc   = ['name' => '张三', 'age' => 28];       // 键: name, age

// 键的隐式转换
$mixed = [
    0     => 'int_zero',
    "0"   => 'str_zero',   // "0" → 整数 0,覆盖上一行
    true  => 'bool_true',  // true → 1
    1.7   => 'float',      // 1.7 → 1,覆盖 true 那行
    null  => 'null_key',   // null → ""
];
// 最终: [0 => 'str_zero', 1 => 'float', '' => 'null_key']
echo count($mixed); // 3

// array_merge() vs +
$a = [0 => 'a', 1 => 'b'];
$b = [0 => 'c', 1 => 'd'];

$merged = array_merge($a, $b);
// [0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'] — 整数键重编号,全保留

$union = $a + $b;
// [0 => 'a', 1 => 'b'] — 键冲突保留左侧

// PHP 8.1+: array_is_list() 判断是否为索引数组
var_dump(array_is_list([1, 2, 3]));         // true
var_dump(array_is_list([0 => 1, 2 => 3]));  // false(不连续)
var_dump(array_is_list(['a' => 1]));        // false(字符串键)

基于 Apache License 2.0 开源