一、array_map()是做什么的
PHP内置的array_map()函数,作用是把一个或多个数组的每个值交给用户自定义函数处理,然后返回一个装满了新值的数组。它从PHP4.0.6开始就有了,算是PHP数组函数库里比较早的一员。
一句话概括它的行为:数组进,数组出,中间隔着你的回调函数。
语法形式:
array array_map ( callable $callback , array $array1 [, array $... ] )
参数上,$callback是必须的,可以是自定义函数名、匿名函数,也可以是null。$array1是必须的,后面还可以跟$array2、$array3等等,都是可选的。
返回值是一个数组,内容是$array1里的值经过回调函数处理之后的结果。
这里有个点需要留意:array_map()返回的新数组,键名会保留$array1的键名,但仅限单数组的情况。多个数组同时传入时,返回的是从0开始的连续索引,这一点后面会举例说明。
二、单数组映射:一个进,一个出
先看最基础的用法,用代码号学习编程的示例来讲:
<?php
function square($n)
{
return $n * $n;
}
$nums = array(1, 2, 3, 4, 5, 6);
$result = array_map("square", $nums);
print_r($result);
?>
输出:
Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 16 [4] => 25 [5] => 36 )
$nums里的每个数字依次被square()处理,返回平方值,之后拼成一个新数组。原数组$nums本身没有被改动,这是array_map()的一个特点:它不修改原数组,而是返回一个新数组。
再换个场景,做字符串替换:
<?php
function fixName($x)
{
if ($x === "virat") {
return "kapil";
}
return $x;
}
$a = array("sachin", "virat", "dhoni");
print_r(array_map("fixName", $a));
?>
输出:
Array ( [0] => sachin [1] => kapil [2] => dhoni )
这个例子的逻辑很简单:匹配到virat就换成kapil,其他原样返回。项目开发里,这种"满足条件就改,不满足就留"的映射模式很常见,比如统一格式化用户名、替换敏感词、批量修正数据等。
我个人的习惯是,回调函数里的判断尽量保持单一职责。如果替换规则超过三条,我会考虑用switch或者映射表,而不是一路if堆下去,不然过几天回来看会头疼。
三、多数组并行处理:几个进,一个出
array_map()支持一次传多个数组,回调函数按位置同时接收来自各个数组的元素。数组长度不一致时,短的会被补成null。
<?php
function compare($a1, $a2)
{
if ($a1 === $a2) {
return "like";
}
return "unlike";
}
$x1 = array("sachin", "virat", "rahul");
$x2 = array("pujara", "virat", "hardik");
print_r(array_map("compare", $x1, $x2));
?>
输出:
Array ( [0] => unlike [1] => like [2] => unlike )
$x1[0]和$x2[0]一起进compare(),$x1[1]和$x2[1]一起进,依次类推。这种写法在对比两组数据、计算两个数组对应元素的差值、合并两个列表时挺实用。
多数组模式下返回的数组索引是从0开始的连续整数,不再保留原数组的键名。如果你依赖键名做后续处理,这一步要提前想清楚。
回调函数的参数个数要和传入的数组个数对应上。传三个数组,回调就得接三个参数,少一个会报错,多一个用不上也没意义。
四、null作回调:把多个数组合并成二维数组
array_map()的第一个参数允许传null,这时它会把传入的多个数组按位置"拉链式"组合成一个二维数组。
<?php
$a = array('a', 'b', 'c');
$b = array(100, 200, 300);
$result = array_map(null, $a, $b);
print_r($result);
?>
输出:
Array (
[0] => Array ( [0] => a [1] => 100 )
[1] => Array ( [0] => b [1] => 200 )
[2] => Array ( [0] => c [1] => 300 )
)
这个用法在整理数据时挺好用。比如你有两列数据,一列是名称,一列是数值,想按行配对成一个二维结构,array_map(null,...)一行就能搞定,不用写循环。
不过传null时只能传一个数组的话,返回的还是原数组的副本,意义不大。这个特性主要在多数组场景下才有价值。
五、和foreach、array_walk的区别
这是很多人会问的问题:既然foreach能遍历数组,为什么还要用array_map()?
我的理解是这样:
foreach是通用的遍历工具,适合边遍历边做各种操作,包括修改原数组、累加、输出、跳出循环等。它的定位是"过程控制"。
array_map()的定位更窄,它专门做"映射"——把每个元素变换成另一个值,然后收集成新数组。它不修改原数组,也不适合做累加、过滤这类操作。代码意图上,array_map()比foreach更明确:看到它就知道这里在做映射。
array_walk()则不同,它也是遍历数组并调用回调,但回调接收的是值和键,而且它直接作用于原数组(回调里用引用可以改原数组),返回值是布尔值而不是新数组。所以array_walk()更适合"原地修改",array_map()更适合"生成新数组"。
选择的时候,看你要的是什么:要新数组,用array_map();要改原数组,用array_walk();逻辑复杂、需要流程控制,用foreach。工具没有高下,看场景。
六、几个项目开发中的注意点
回调里不要依赖外部变量做副作用。array_map()的设计意图是纯映射,如果你在回调里写文件、改全局变量、发请求,代码会变得难读也难测。这类操作放foreach里更合适。
匿名函数用use传参要留意。PHP的匿名函数默认不能访问外部变量,需要use引入。引入对象时是值传递,想改外部变量得用引用,但那样又违背了映射的初衷。
数组键名的保留规则。单数组时保留键名,多数组时重置为连续索引。这个差异在项目里踩过一次坑,处理关联数组时如果后面还要按键取值,得多想一步。
性能不是首要考量。array_map()和foreach在性能上的差距,在大多数业务场景里可以忽略。选哪个主要看代码可读性和意图表达,不必为了微小的性能差异牺牲清晰度。
七、本节课程知识要点
-
array_map()把数组元素交给回调处理,返回新数组,不修改原数组。 -
回调可以是函数名、匿名函数,也可以是
null。 -
单数组映射保留原键名,多数组映射返回从0开始的连续索引。
-
多数组长度不一致时,短的补
null。 -
null作回调时,多个数组按位置组合成二维数组。 -
映射用
array_map(),原地修改用array_walk(),复杂流程用foreach。 -
回调函数保持纯粹,避免副作用,代码更好维护。