在 PHP 面试中,array_map、array_walk 和 array_filter 是三个经常被拿来对比的数组函数。它们都可以对数组中的每个元素执行某种操作,但各自的设计目的、返回值、回调参数和使用场景有显著差异。很多候选人在实际开发中能“用对”,却未必能“说清”。本文将从底层机制、典型用法和常见陷阱三个维度,帮你彻底理清它们的区别。
一、核心定位:它们各自解决什么问题
先给出最简洁的结论:
- array_map:对数组每个元素执行回调,返回一个新数组,原数组不变。核心是“映射/转换”。
- array_walk:对数组每个元素执行回调,返回布尔值,通常用于“就地修改”原数组。核心是“遍历并副作用操作”。
- array_filter:用回调过滤数组元素,返回过滤后的新数组,原数组不变。核心是“筛选”。
记住这三个关键词:映射、遍历、筛选,后续所有差异都由此衍生。
二、返回值与参数签名对比
| 特性 | array_map | array_walk | array_filter |
|---|---|---|---|
| 返回值 | 新数组 | bool | 新数组 |
| 是否修改原数组 | 否 | 可修改(引用) | 否 |
| 回调参数 | 值(可多数组) | 值 + 键 + 额外参数 | 值(键可选) |
| 支持多数组 | 是 | 否 | 否 |
| 键是否保留 | 否(重新索引) | 不涉及 | 是(保留原键) |
| 回调返回值作用 | 作为新值 | 仅作流程控制 | 决定是否保留 |
这张表建议面试时直接背下来,能覆盖 80% 的追问。
三、array_map 详解
基本用法
$arr = [1, 2, 3, 4];
$result = array_map(function($n) {
return $n * 2;
}, $arr);
// $result = [2, 4, 6, 8]
// $arr 仍然是 [1, 2, 3, 4]
多数组同时处理
这是 array_map 独有的能力,面试常考:
$a = [1, 2, 3];
$b = [10, 20, 30];
$result = array_map(function($x, $y) {
return $x + $y;
}, $a, $b);
// [11, 22, 33]
多数组时,长度以最长数组为准,短数组会用 null 补齐。
关键注意点
- 如果传入
null作为回调,array_map会返回原数组的副本,可用于“重新索引”或“去除引用”。 - 字符串键会被丢弃,返回数组始终是连续整数索引。这是与
array_filter的重要区别。 - 回调返回什么,新数组元素就是什么,返回
null也会被保留。
四、array_walk 详解
基本用法
$arr = [1, 2, 3];
array_walk($arr, function(&$value, $key) {
$value = $value * 2;
});
// $arr 变为 [2, 4, 6]
注意回调第一个参数是引用 &$value,这是能修改原数组的关键。如果不加 &,修改不会生效——这是面试高频陷阱。
第三个参数
array_walk 支持传入额外参数,会作为回调的第三个参数:
$arr = ['a', 'b'];
array_walk($arr, function($value, $key, $prefix) {
echo $prefix . $value;
}, 'item_');
// 输出 item_a item_b
关键注意点
- 返回布尔值,成功
true,失败false。不要试图接收它的“结果数组”。 - 回调的返回值被忽略,只用于控制流程(但实际中很少这样用)。
- 如果要修改键,需要用
&$key,且 PHP 对键的修改支持有限,实践中不推荐。 - 相比
foreach,array_walk更函数式,但可读性未必更好。
五、array_filter 详解
基本用法
$arr = [1, 0, 2, null, 3, '', 4];
$result = array_filter($arr);
// [1, 2, 3, 4](默认过滤掉假值)
不传回调时,array_filter 会过滤掉所有“假值”:false、null、0、''、[]、'0'。注意 '0' 和 0 也会被过滤,这是常见坑。
带回调
$arr = [1, 2, 3, 4, 5];
$result = array_filter($arr, function($n) {
return $n % 2 === 1;
});
// [1, 3, 5]
使用 ARRAY_FILTER_USE_KEY 和 ARRAY_FILTER_USE_BOTH
PHP 5.6+ 支持回调接收键:
$arr = ['a' => 1, 'b' => 2, 'c' => 3];
$result = array_filter($arr, function($key) {
return $key !== 'b';
}, ARRAY_FILTER_USE_KEY);
// ['a' => 1, 'c' => 3]
ARRAY_FILTER_USE_BOTH 则同时传入值和键。
关键注意点
- 保留原键。过滤后键不会重新索引,如果后续需要连续索引,要配合
array_values()。 - 回调只需返回布尔值,
true保留,false过滤。 - 默认行为容易误伤
0和'0',过滤数字时建议显式传回调。
六、三者对比的经典面试题
题目:把数组 [1, 2, 3, 4, 5] 中的偶数翻倍,并只保留结果大于 5 的元素。
用三个函数分别实现:
$arr = [1, 2, 3, 4, 5];
// 方案一:array_map + array_filter
$step1 = array_map(fn($n) => $n % 2 === 0 ? $n * 2 : $n, $arr);
$result = array_filter($step1, fn($n) => $n > 5);
// [8, 10]
// 方案二:array_walk + array_filter
$temp = $arr;
array_walk($temp, function(&$v) {
if ($v % 2 === 0) $v *= 2;
});
$result = array_filter($temp, fn($n) => $n > 5);
// 方案三:array_filter + array_map(顺序不同)
$filtered = array_filter($arr, fn($n) => $n % 2 === 0);
$result = array_map(fn($n) => $n * 2, $filtered);
// [4, 8] —— 注意结果不同!
这个例子说明:函数的执行顺序会影响结果,面试时可以主动指出这一点,展示你对数据流的理解。
七、性能与选择建议
- 纯转换用
array_map,语义最清晰。 - 纯筛选用
array_filter。 - 需要就地修改、或需要键和额外参数时用
array_walk。 - 如果只是简单遍历且不需要返回值,
foreach往往比array_walk更直观、性能也略好。 - 链式调用时注意
array_filter保留键的问题,必要时用array_values重置。
八、一句话总结
array_map 管“变成什么”,array_filter 管“留下什么”,array_walk 管“对每个元素做点什么”。 返回值、是否修改原数组、键的处理方式,是区分它们的三把钥匙。面试中能把这三点讲清楚,并指出 array_filter 默认过滤假值和保留键这两个陷阱,基本就能拿到高分。
未经允许不得转载:任鹏个人博客 » PHP 面试题:PHP 数组函数 array_map、array_walk、array_filter 的区别

