← PHP array_values函数详解:提取数组值并重建数字索引 PHP字符串引用是什么?能解决哪些实际问题 →

PHP array_walk函数详解:遍历数组并施加自定义回调

著
原创 2026-10-09 PHP 已有人查阅

一、函数定位与核心机制

array_walk是PHP内置的数组遍历函数,从PHP4.0开始提供。它的作用是把用户自定义的函数应用到数组的每一个元素上。

名字里的walk可以理解为「走过一遍」,逐个访问数组元素,每访问一个就调用一次回调。

这个函数和array_map容易混,但两者的设计思路不同:

  • array_map:把数组元素映射成新值,返回一个新数组,不修改原数组

  • array_walk:遍历数组元素,回调通过引用可以直接修改原数组,返回布尔值

简单说,array_map是「转换」,array_walk是「访问并可能修改」。这个区别决定了它们的适用场景。

语法结构

bool array_walk(array &$array, callable $callback, mixed $userdata = null): bool

参数说明:

参数 是否必需 说明
array 必需 输入数组,传引用
callback 必需 用户自定义的回调函数
userdata 可选 传递给回调的第三个参数

返回值是布尔值:成功返回true,失败返回false。

回调参数顺序

array_walk的回调接收两个必需参数,顺序是值在前、键在后:

function codehub_callback($value, $key) {
    // $value 是当前元素的值
    // $key 是当前元素的键名
}

这个顺序和很多人的直觉相反。一般说到「键值对」,习惯先键后值,但array_walk的回调是先值后键。这一点在第一次用时容易写反,导致输出结果错位。写反了不会报错,只是逻辑不对,排查起来要花点时间。

如果传了userdata,回调的第三个参数会收到它:

function codehub_callback($value, $key, $extra) {
    // $extra 是 userdata 传进来的值
}

二、传引用修改原数组

array_walk的第一个参数是&$array,传引用。但更关键的是,回调的第一个参数也可以声明为引用,这样就能直接修改数组元素的值。

$numbers = array(1, 2, 3, 4);
array_walk($numbers, function(&$value, $key) {
    $value = $value * 2;
});
print_r($numbers);

输出:

Array
(
    [0] => 2
    [1] => 4
    [2] => 6
    [3] => 8
)

回调参数前加了&,value成为原数组元素的引用,赋值直接改写原数组。如果回调参数不加`&`,value是副本,修改它不影响原数组。

这是array_walk和array_map的一个核心差异。array_map无法修改原数组,只能返回新数组;array_walk通过引用可以直接改写原数组,节省一次数组复制。

个人经验:在批量格式化数据的场景里,比如把用户列表里的手机号中间四位打码、把金额字段统一转成两位小数,array_walk配合引用比array_map更直接。array_map需要接收返回值再赋回原变量,array_walk一步到位。不过要注意,如果原数组后续还要用到原始数据,就不能用引用修改,得先用array_map生成新数组。

三、userdata第三参数的用法

第三个参数userdata是可选的,传给回调作为第三个参数。它的作用是把外部数据带进回调,避免用全局变量。

$prefix = "codehub_";
$langs = array("php", "java", "python");
array_walk($langs, function($value, $key, $prefix) {
    echo $prefix . $value . "\n";
}, $prefix);

输出:

codehub_php
codehub_java
codehub_python

不用userdata的话,就得把$prefix声明成全局变量,或者用use关键字闭包捕获。userdata提供了更干净的传参方式。

注意一点:userdata是按值传递的,回调里修改它不会影响外部变量。如果需要回调修改外部数据,得传引用或者用对象。

四、项目实战示例

示例一:基础遍历输出

<?php
function codehub_show($value, $key) {
    echo "The key $key has the value $value \n";
}

$tech = array("a" => "", "b" => "google", "c" => "whatsapp");
array_walk($tech, "codehub_show");

输出:

The key a has the value 
The key b has the value google
The key c has the value whatsapp

回调先接收值,再接收键。遍历顺序按数组内部顺序,不额外排序。

示例二:带前缀的遍历

<?php
function codehub_prefix($value, $key) {
    echo "codehub $key has $value \n";
}

$tutorials = array("tutorial1" => "php", "tutorial2" => "java", "tutorial3" => "python");
array_walk($tutorials, "codehub_prefix");

输出:

codehub tutorial1 has php
codehub tutorial2 has java
codehub tutorial3 has python

回调里拼接固定前缀,适合生成日志、生成报告标题这类场景。

示例三:引用修改数组元素

<?php
$prices = array("apple" => 5, "banana" => 3, "orange" => 4);
array_walk($prices, function(&$value, $key) {
    $value = $value * 1.1;
});
print_r($prices);

输出:

Array
(
    [apple] => 5.5
    [banana] => 3.3
    [orange] => 4.4
)

回调参数加引用,直接改写原数组的值。这个用法在批量调价、批量格式转换场景里很实用。

示例四:用userdata传外部配置

<?php
$config = array("prefix" => "news_", "suffix" => "_2026");
$news = array("a" => "aajtak", "b" => "zee", "c" => "ndtv");

array_walk($news, function($value, $key, $config) {
    echo $config["prefix"] . $value . $config["suffix"] . "\n";
}, $config);

输出:

news_aajtak_2026
news_zee_2026
news_ndtv_2026

userdata可以传数组,把多个外部参数打包进去。这样回调不用依赖全局变量,代码更清晰。

示例五:结合键名做条件处理

<?php
$scores = array("math" => 88, "english" => 72, "science" => 95);
array_walk($scores, function(&$value, $key) {
    if ($key === "english") {
        $value = $value + 5;
    }
});
print_r($scores);

输出:

Array
(
    [math] => 88
    [english] => 77
    [science] => 95
)

回调里可以根据键名做条件判断,只修改特定元素。这个能力是array_map不具备的,因为array_map的回调拿不到键名。

五、容易踩的坑

回调参数顺序写反。array_walk的回调是先值后键,和很多人的直觉相反。写反了不报错,但逻辑全错。这一点在第一次用时容易中招。

想修改原数组但回调参数没加引用。回调参数不加&,$value是副本,修改它不影响原数组。很多人以为array_walk传引用了就能改原数组,实际上第一个参数的引用只保证函数能操作原数组,回调里的修改还需要单独加引用。

userdata不能直接修改外部变量。userdata按值传递,回调里改它不影响外部。需要修改外部数据时,传引用或传对象。

回调里不要做重操作。array_walk遍历整个数组,每个元素调用一次回调。如果回调里做数据库查询、文件读写、网络请求,性能会随数组长度线性下降。这类操作应该先批量查询,再在回调里做内存处理。

array_walk不返回新数组。它的返回值是布尔值,不是处理后的数组。如果需要处理后的新数组,用array_map。如果需要同时保留原数组和处理结果,可以用array_map生成新数组,或者复制一份原数组再用array_walk引用修改。

对多维数组只处理最外层。array_walk只遍历最外层元素,子数组会被当作一个值传给回调。如果需要递归处理多维数组,用array_walk_recursive。这一点在树形结构数据处理时要注意。

回调不能是内置函数。像strtoupper、trim这类内置函数,参数签名和array_walk的回调不匹配(内置函数通常只接收一个参数,或者参数顺序不同),直接传给array_walk会报错。要包装成闭包再用:

array_walk($arr, function(&$v, $k) {
    $v = strtoupper($v);
});

六、知识点笔记

  • array_walk遍历数组,对每个元素调用一次回调

  • 回调参数顺序是值在前、键在后

  • 回调参数声明为引用时,可以直接修改原数组元素

  • 第一个参数传引用,函数操作原数组

  • 返回布尔值,成功true,失败false

  • userdata是可选的第三参数,按值传递给回调

  • 与array_map的区别:array_walk可修改原数组、能拿到键名、不返回新数组

  • 多维数组递归处理用array_walk_recursive

  • 回调里避免做数据库查询、网络请求这类重操作

七、适用场景

这个函数适合以下场景:

  • 批量格式化数组元素(金额、日期、字符串)

  • 遍历数组生成日志或报告

  • 需要按键名做条件处理的场景

  • 需要直接修改原数组、不想生成新数组的场景

  • 多维数组递归处理(用array_walk_recursive)

不适合的场景:

  • 需要返回新数组、保留原数组不变,用array_map

  • 简单的元素转换,用array_map更直观

  • 需要过滤元素,用array_filter

  • 需要聚合结果,用array_reduce

← PHP array_values函数详解:提取数组值并重建数字索引 PHP字符串引用是什么?能解决哪些实际问题 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号