array_filter() 是最直接安全的数组过滤方案,不修改原数组、保留键名;默认过滤所有假值(含0、空字符串等),需注意业务中0是否合法;可通过回调函数及ARRAY_FILTER_USE_KEY/BOTH等标志精确控制过滤逻辑。

array_filter() 是最直接、最安全的方案,不用手动遍历或 unset,也不会破坏键名结构。它不修改原数组,返回新数组,语义清晰且性能稳定。
默认行为会悄悄删掉 0、null、空字符串和 false
不传回调函数时,array_filter($array) 会按 PHP 的“空值判断规则”过滤:所有等价于 false 的值都会被剔除,包括 0、0.0、''、null、false、[](空数组)。
这在清理表单输入或 API 响应时很常用,但要注意——如果你的业务逻辑中 0 是合法值(比如商品库存为 0),这种默认用法就会出错。
- 常见误判场景:用户提交了数量
0,结果被当成无效值过滤掉了 - 调试线索:输出结果里突然少了某个已知存在的键,检查下对应值是不是
0或'' - 替代方案:显式写回调,只过滤你真正想剔除的类型,例如
is_null($value) || $value === ''
用回调函数精确控制保留逻辑
传入回调后,array_filter() 就完全交由你定义“什么算符合条件”。回调接收单个参数(默认是值),返回 true 才保留。
立即学习“PHP免费学习笔记(深入)”;
示例:只保留非空字符串且长度大于 2 的元素
$data = ['a', 'hi', 'hello', '', null, 'x'];
$result = array_filter($data, function($value) {
return is_string($value) && strlen($value) > 2;
});
// 结果: ['hello'],键为原键 2
- 回调里别调用
unset或修改正在被过滤的数组,行为未定义 - PHP 7.4+ 可用箭头函数简化:`fn($v) => is_numeric($v) && $v > 10`
- 若需对每个元素做较重计算(如数据库查询),先考虑是否真要在这里过滤,避免 N+1
需要按键名或同时看键和值?用 flag 参数
默认回调只拿到值;加 ARRAY_FILTER_USE_KEY 就只拿键;加 ARRAY_FILTER_USE_BOTH 才同时拿到键和值——这是处理配置项、白名单字段、多维映射时的关键能力。
示例:只保留键名为 'id'、'name'、'email' 的字段
$user = ['id' => 123, 'name' => 'Alice', 'age' => 28, 'email' => 'a@b.c'];
$whitelist = array_filter($user, function($value, $key) {
return in_array($key, ['id', 'name', 'email']);
}, ARRAY_FILTER_USE_BOTH);
// 结果: ['id'=>123, 'name'=>'Alice', 'email'=>'a@b.c']
-
ARRAY_FILTER_USE_KEY适合纯键名过滤,比如只留数字键:is_int($key) - flag 是整数常量,不能写成字符串
"ARRAY_FILTER_USE_BOTH",否则静默失效 - PHP 8.0+ 支持
ARRAY_FILTER_USE_VALUE,但和默认行为一样,基本不用显式写
过滤完索引乱了?别急着 array_values()
array_filter() 默认保留原始键名,这对关联数组(如数据库记录、配置数组)是优点,不是 bug。只有当你明确需要连续数字索引(比如给前端渲染列表),才该补一句 array_values()。
错误做法:每次过滤都无脑套 array_values(array_filter(...))
- 如果原数组是索引数组且你依赖顺序,那没问题
- 但如果原数组是
['status'=>'active', 'created_at'=>...]这种,array_values()会把键变成[0=>'active', 1=>...],后续代码可能因键名丢失而报错 - 更稳妥的做法:先确认业务是否真的需要重索引,再决定是否加
array_values()
真正容易被忽略的是 flag 参数的类型检查和回调中对变量类型的防御——比如用 $value > 10 判断时,如果某元素是字符串 'abc',PHP 会转成 0 再比,结果可能不符合预期。写回调前,先想清楚输入可能有哪些类型。



















