array_filter() 默认去所有 falsy 值(null、false、0、0.0、''、[]),非仅“去空”;会重排键名,且 0 也被删除,语义为“去假值”而非“去空”。

array_filter() 默认行为为什么能去空值
array_filter() 不传回调函数时,会用 PHP 内部的“truthy/falsy 判断逻辑”过滤掉所有 falsy 值:包括 null、false、0、0.0、空字符串 ''、空数组 []。这不是“去空”,而是“去假值”——这点常被误读为“去空字符串”或“去 null”,实际它连 0 都会删掉。
常见错误现象:
原数组有 [1, 0, 'hello', ''],用 array_filter($arr) 后变成 [1 => 1, 2 => 'hello'],0 消失了,且键名重排(非连续索引)。
- 若你只要剔除
null和'',但保留0和false,就不能直接用默认array_filter() - 默认调用是 C 层实现,无 PHP 回调开销,速度最快 —— 但语义不精确
- PHP 8.0+ 中,
array_filter($arr, fn($v) => $v !== '' && $v !== null)这类匿名函数写法比传统function(){}快约 15%,但仍慢于无回调版本
foreach 手动遍历在什么场景下反而更稳
当你要精准控制“空”的定义(比如只删 null,保留 '';或删 '' 和 null,但留 0),foreach 是最透明、最可控的方式。
实操建议:
用引用赋值 + unset() 可避免重建数组,节省内存;但注意键名不会自动重排:
立即学习“PHP免费学习笔记(深入)”;
foreach ($arr as $k => &$v) {
if ($v === null || $v === '') {
unset($arr[$k]);
}
}
- 不推荐
$new[] = $v方式重建,小数组无感,大数组(>10 万元素)会多一次内存分配 - PHP 7.4+ 支持箭头函数,但无法用于带
unset的复杂逻辑,此时还是传统foreach更直接 - 如果后续要
array_values()重排索引,记得单独加——这一步是 O(n) 开销,别漏掉
array_diff() 和 array_filter() 性能差多少
array_diff($arr, [null, '']) 看似简洁,但它是为“比较多个数组差异”设计的,底层会做哈希键映射和全量扫描,对单数组去空属于杀鸡用牛刀。
基准测试(10 万元素纯数值+字符串混合数组,PHP 8.2):
– array_filter($arr):≈ 1.8 ms
– array_filter($arr, fn($v) => $v !== null && $v !== ''):≈ 4.2 ms
– array_diff($arr, [null, '']):≈ 9.7 ms
– 手动 foreach + unset:≈ 2.1 ms
-
array_diff()在内部会把第二个参数转为键值对并去重,哪怕你只传两个值,它也走完整 diff 流程 - 如果数组含非标量值(如对象、资源),
array_diff()直接报Warning: Array to string conversion - 不要为了“看起来函数式”而选
array_diff()—— 语义错、性能差、容错弱
PHP 8.3 的 array_filter() 新特性值得升级吗
PHP 8.3 引入了 ARRAY_FILTER_USE_KEY 和 ARRAY_FILTER_USE_BOTH 标志,但它们解决的是“按键过滤”或“键值联合判断”问题,**并不加速纯值过滤**,也不改变默认去 falsy 的行为。
也就是说:如果你的需求仍是“去掉空字符串和 null”,PHP 8.3 并没给你更快的原生方案。真正提速的点在于 JIT 编译优化和引擎底层改进,而非这个函数本身。
- 升级到 8.3 后,
array_filter($arr, ...)的回调执行确实略快(约 3~5%),但前提是用了 JIT 且代码热路径足够长 - 若你用的是 OpCache + 静态编译,PHP 8.1 和 8.3 在该操作上差距可忽略
- 别为单个函数升级 PHP 大版本——先确认你的“空”到底指什么,再选方法,比版本更重要
'',后端却用 array_filter() 把 0 也干掉了,结果数字字段莫名消失——这种问题不会出现在 benchmark 里,但天天发生在联调现场。











