一、函数定位与核心机制
array_values是PHP内置的数组处理函数,从PHP4.0开始提供。它的作用很直接:把数组里的所有值提取出来,组成一个新的索引数组。
用一句话概括它的行为:丢掉键名,只留值,重新从0开始编号。
这个名字里没有u,没有assoc,没有sort,因为它做的事情非常单一。它不比较、不排序、不去重,只是把键值对里的值那部分抽出来,重新打包成一个连续索引的数组。
语法结构
array array_values(array $array): array
参数说明:
| 参数 | 是否必需 | 说明 |
|---|---|---|
| array | 必需 | 输入数组 |
返回值是一个新数组,包含原数组的所有值,键名从0开始,依次加1。原数组不被修改,函数不传引用。
键名重建规则
原文里有一条重要说明:返回的数组使用数字键名,从0开始,每次加1。
这条规则不分原数组的键名类型。不管是字符串键名、数字键名、还是混合键名,结果数组的键名都是0、1、2、3这样的连续整数。
$arr = array(5 => "a", 10 => "b", "name" => "c");
print_r(array_values($arr));
输出:
Array
(
[0] => a
[1] => b
[2] => c
)
原来的5、10、name全部丢弃,重新编号成0、1、2。值的顺序保持不变,还是按原数组里的顺序排列。
二、与相近函数的区分
array_values和几个相关函数经常被放在一起比较,这里做一次梳理:
| 函数 | 作用 | 返回内容 |
|---|---|---|
| array_keys | 提取键名 | 键名组成的索引数组 |
| array_values | 提取值 | 值组成的索引数组 |
| array_flip | 键值互换 | 键名变值,值变键名 |
| array_combine | 合并键值 | 用两个数组合成一个关联数组 |
array_values和array_keys是一对反向操作。前者取值,后者取键。在调试时,如果只想看数组里有哪些值,用array_values;如果只想看有哪些键,用array_keys。
个人经验:在接口返回数据时,如果数据源是一个关联数组,但前端期望拿到一个数组格式(JSON里的[]而不是{}),就需要用array_values处理一下。PHP的json_encode会把连续数字索引的数组编码成JSON数组,把关联数组编码成JSON对象。这个差异在前端联调时经常引发问题,明明后端返回的是列表,前端拿到的却是对象。
三、JSON输出场景的实际价值
这一点值得单独展开,因为它是array_values在项目里最常见的用途之一。
PHP数组在json_encode时的行为:
$list1 = array("a", "b", "c");
echo json_encode($list1);
// 输出:["a","b","c"]
$list2 = array("x" => "a", "y" => "b");
echo json_encode($list2);
// 输出:{"x":"a","y":"b"}
如果数组经过某些操作(比如array_filter、array_unique)后键名变得不连续,json_encode会把它当成关联数组处理:
$data = array("a", "b", "c");
$filtered = array_filter($data, function($v) {
return $v !== "b";
});
echo json_encode($filtered);
// 输出:{"0":"a","2":"c"}
键名是0和2,不连续,json_encode输出成对象。前端拿到的就不是数组,遍历方式、长度判断都会出问题。
用array_values包一层:
echo json_encode(array_values($filtered));
// 输出:["a","c"]
问题解决。这个用法在接口开发里出现频率很高,尤其是数据经过过滤、去重、排序之后。
四、项目实战示例
示例一:数字键名数组取值
<?php
$a = array(1 => "javatpoint", 2 => "udemy", 3 => "byjus");
print_r(array_values($a));
输出:
Array
(
[0] => javatpoint
[1] => udemy
[2] => byjus
)
原来的键名1、2、3被丢弃,重新编号成0、1、2。
示例二:字符串键名数组取值
<?php
$a = array("a" => "apple", "b" => "ball", "c" => "cat");
print_r(array_values($a));
输出:
Array
(
[0] => apple
[1] => ball
[2] => cat
)
字符串键名全部丢弃,值按原顺序保留。
示例三:混合键名数组取值
<?php
$game = array("a" => "mario", "b" => "need for speed", "c" => "igi", "road race");
print_r(array_values($game));
输出:
Array
(
[0] => mario
[1] => need for speed
[2] => igi
[3] => road race
)
这个示例里"roadrace"没有指定键名,PHP自动分配了下一个数字索引。array_values处理后,所有键名统一重建成0、1、2、3。
示例四:配合array_filter输出JSON数组
<?php
$scores = array(88, 0, 72, 0, 95);
$passed = array_filter($scores, function($v) {
return $v > 0;
});
echo json_encode(array_values($passed));
输出:
[88,72,95]
array_filter去掉了值为0的元素,但保留了原键名0、2、4。直接json_encode会输出{"0":88,"2":72,"4":95},前端拿到的是对象。用array_values重新索引后,输出标准的JSON数组。
示例五:取关联数组的值做批量处理
<?php
$person = array("Name" => "Tom", "Age" => 30, "Country" => "China");
$values = array_values($person);
foreach ($values as $v) {
echo $v . "\n";
}
输出:
Tom
30
China
当只需要处理值、不关心键名时,先array_values提取出来,后续逻辑可以按索引访问,代码更简洁。
五、容易踩的坑
误以为会修改原数组。array_values返回新数组,原数组不变。这一点和usort、array_unshift这些传引用的函数不同。如果业务上想用结果替换原数组,需要显式赋值:
$arr = array_values($arr);
键名信息丢失后无法恢复。array_values丢弃键名,如果后续逻辑需要按原键名访问,就没办法了。调用之前先确认键名是否还有用。
多维数组只处理最外层。array_values只重建最外层的键名,子数组的键名不受影响。如果子数组也是关联数组,需要递归处理或手动遍历。
对已经是索引数组的数组调用没有副作用。如果原数组已经是0、1、2连续索引,array_values返回一个内容相同的新数组。功能上没变化,但会多占一份内存。在内存敏感的场景下,先判断一下是否必要。
性能开销。array_values需要遍历整个数组,时间复杂度是O(n)。对超大数组(几十万条以上)频繁调用,会带来可观的开销。如果只是为了让json_encode输出数组格式,可以在数据源头就保持索引连续,减少这类转换操作。
和array_column的区别。array_column是从多维数组里提取某一列的值,array_values是提取一维数组的所有值。两者用途不同,不要混用。比如从用户列表里提取所有用户名的数组,用array_column(users,′name′);把用户列表的键名去掉重新索引,用arrayvalues(users,′name′);把用户列表的键名去掉重新索引,用arrayvalues(users)。
六、知识点总结
-
array_values提取数组的所有值,返回新的索引数组
-
返回数组的键名从0开始,依次加1,连续排列
-
原数组的键名类型不影响结果,字符串键名和数字键名都会被丢弃
-
原数组不被修改,函数不传引用
-
值的顺序保持不变
-
与array_keys是反向操作,一个取值一个取键
-
配合json_encode使用时,可以保证输出JSON数组而不是对象
-
对已经是连续索引的数组调用会多占一份内存
七、适用场景
这个函数适合以下场景:
-
数据经过array_filter、array_unique等操作后键名不连续,需要重新索引
-
接口返回列表数据,需要保证json_encode输出数组格式
-
只需要处理值、不关心键名的场景
-
把关联数组转成索引数组,方便用for循环遍历
不适合的场景:
-
需要保留键名的场景,用asort或uasort排序后保留键名
-
需要按键名访问数据的场景
-
只需要某一列的值,用array_column更直接
-
超大数组且键名已经连续的场景,调用会多占内存