empty() 将 0、"0"、false、""、null、[] 视为“空”并返回 true,其中 "0" 是最易被忽略的陷阱;isset() 和 is_null() 才专用于判断 null,对 0、false、"" 均返回 false。

empty() 判定哪些值为 true(即“非空”)
empty() 不是判断是否为 null,而是检测变量是否“被认为为空”——它会把 0、"0"、false、""、null、[] 都当作“空”。这是最容易踩坑的地方:比如 empty("0") 返回 true,但字符串 "0" 显然不是 null,也不是逻辑假值(在松散比较中它会被转成整数 0,但本身有内容)。
实际过滤数组时,如果用 array_filter($arr, 'empty'),会把所有“空值”都剔除,包括你可能想保留的 "0" 或 0。这不是 bug,是设计如此。
-
empty(null)→true -
empty(0)→true -
empty("0")→true(注意:这个常被忽略) -
empty([])→true -
empty("false")→false(字符串内容不为空)
isset() 和 is_null() 才是 null 的“正统裁判”
要精准区分 null 和其他“空”,得换函数:isset() 检查变量是否存在且不为 null;is_null() 则只认准 null 本身。它们对 0、false、"" 全部返回 false,和 empty() 行为截然不同。
例如过滤掉真正未设置或显式设为 null 的键值,应该用:
立即学习“PHP免费学习笔记(深入)”;
array_filter($arr, function($v) { return !is_null($v); })
或者更严格地连未定义键也排除(配合 isset):
array_filter($arr, 'isset')
-
isset(null)→false -
is_null(null)→true -
isset(0)→true(存在且非 null) -
is_null("0")→false
array_filter() 默认行为其实等价于 !empty()
当 array_filter() 第二个参数省略时,它内部就是对每个值调用 empty() 做判定。也就是说,array_filter([0, "0", null, false, "ok"]) 结果是 ["ok"],中间四个全被干掉了——哪怕其中只有 null 是你真正想筛掉的。
如果你的目标只是清理“无效数据”,这没问题;但若业务上 0 是合法状态(比如商品库存为 0),那就必须显式传入回调,否则数据就丢了。
- 省略回调 = 按
empty()过滤 - 传
'isset'可保留0、false、"",仅剔除null和未定义项 - 传
function($v) { return $v !== null; }最明确,不依赖隐式转换
字符串 "0" 是最隐蔽的陷阱
前端传参、JSON 解析、数据库读取都可能把数字 0 变成字符串 "0"。而 empty("0") === true,isset("0") === true,is_null("0") === false——三者结果完全不同。一旦你在接口层用 empty() 做必填校验,"0" 就会被当成缺失字段拒收。
解决办法很直接:需要数值语义时,先用 (int) 或 filter_var($v, FILTER_VALIDATE_INT) 转型;需要保留原始类型又得过滤,就别碰 empty(),改用 $v !== '' && $v !== null 这类显式判断。
复杂点在于,很多老项目把 empty() 当“非空校验”用,但没意识到它同时吃掉了合法零值。这种逻辑一旦沉淀进通用工具函数,排查起来就得顺着调用链一层层看类型流转。











