在 PHP 面试中,isset()、empty()、is_null() 这三个函数几乎逢面必问。大多数候选人都能说出“一个判断是否设置、一个判断是否为空、一个判断是否为 null”这样的表面答案。但当面试官继续追问“它们对 0、'0'、''、null、false 分别返回什么”“为什么 isset() 不能用于表达式”“empty() 的底层实现是怎样的”时,能完整答对的人并不多。
本文将从语言底层实现出发,逐一拆解这三个函数的本质差异,并整理出面试中常见的连环追问与标准答案。
一、三个函数的本质定位
先给出最核心的结论:
isset()是语言结构(language construct),不是函数。它检查变量是否已声明且值不为null。empty()也是语言结构。它检查变量是否“为空”,而“空”的定义由 PHP 内核的zend_is_true逻辑反向决定。is_null()是真正的函数。它只做一件事:判断值是否严格等于null。
理解“语言结构 vs 函数”的区别非常重要,因为语言结构由编译器直接处理,不能被可变函数调用,也不能被 array_map 等回调直接使用。
二、isset 的底层行为
isset() 在 Zend 引擎中对应 ZEND_ISSET_ISEMPTY_VAR 操作码。它的判断逻辑是:
- 变量在符号表中不存在 → 返回
false - 变量存在但值为
null→ 返回false - 其他任何值,包括
0、''、false、[]→ 返回true
关键点:isset() 只对 null 说“不”。这是它与 empty() 最大的区别。
$a = 0;
var_dump(isset($a)); // true
var_dump(empty($a)); // true
$b = null;
var_dump(isset($b)); // false
var_dump(empty($b)); // true
var_dump(is_null($b)); // true
isset() 还有一个特性:它可以接受多个参数,只有全部设置时才返回 true,且从左到右短路求值。
var_dump(isset($a, $b, $c)); // false,遇到 $b 为 null 即停止
三、empty 的底层行为
empty() 的判断标准来自 Zend 引擎的“假值”集合。以下值会被判定为空:
""(空字符串)0(整数零)0.0(浮点零)"0"(字符串零)nullfalse[](空数组)
注意两个容易踩坑的点:
"0"被认为是空的。这是 PHP 的历史遗留设计,在判断表单输入时经常导致意外。- 未定义的变量使用
empty()不会报错,返回true。而直接使用未定义变量会触发Warning。
var_dump(empty($undefined)); // true,无警告
var_dump($undefined); // Warning: Undefined variable
从底层看,empty() 等价于 !isset($var) || !$var,但它是编译期优化,不会产生 Notice。
四、is_null 的底层行为
is_null() 是标准函数,定义在 ext/standard/type.c 中。它的实现极其简单:
PHP_FUNCTION(is_null)
{
zval *var;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(var)
ZEND_PARSE_PARAMETERS_END();
RETURN_BOOL(Z_TYPE_P(var) == IS_NULL);
}
它只检查 zval 的类型是否为 IS_NULL。因此:
- 未定义变量传入
is_null()会触发Warning,因为它需要先求值。 is_null()只对null返回true,对0、''、false一律返回false。
var_dump(is_null(0)); // false
var_dump(is_null('')); // false
var_dump(is_null(false)); // false
var_dump(is_null(null)); // true
五、三者对比速查表
| 值 | isset() | empty() | is_null() |
|---|---|---|---|
null |
false | true | true |
0 |
true | true | false |
'0' |
true | true | false |
'' |
true | true | false |
false |
true | true | false |
[] |
true | true | false |
| 未定义变量 | false | true | Warning + true |
这张表建议面试前反复默写,它是所有连环追问的基础。
六、面试连环问与标准答案
追问 1:为什么 isset() 不能用于函数返回值?
因为 isset() 是语言结构,参数必须是变量。isset(foo()) 会直接产生语法错误。若需判断返回值是否为 null,应使用 is_null(foo()) 或 foo() === null。
追问 2:empty() 和 !$var 有什么区别?
对于已定义变量,两者结果一致。但 $var 未定义时,!$var 会先触发 Warning,而 empty($var) 不会。此外 empty() 是语言结构,性能略优。
追问 3:判断一个变量“存在且非空字符串”最严谨的写法是什么?
if (isset($var) && $var !== '') { ... }
不要用 !empty($var),因为它会把 '0' 也过滤掉,这在处理订单号、身份证号等场景会造成严重 bug。
追问 4:isset($a, $b) 与 isset($a) && isset($b) 等价吗?
逻辑上等价,但前者是单个操作码,性能更好,且短路行为一致。
追问 5:为什么 empty('0') 是 true?
这是 PHP 早期将字符串 '0' 与整数 0 在布尔上下文统一处理的结果。虽然社区多次讨论修改,但出于兼容性一直保留。面试中能指出这是历史设计而非逻辑必然,会加分不少。
七、实战建议
- 判断变量是否设置用
isset()。 - 判断是否为
null用is_null()或=== null,后者无函数调用开销。 - 判断“非空”时慎用
empty(),若业务上'0'是合法值,必须用isset() && $var !== ''。 - 永远不要依赖
empty()判断未定义变量来“省事”,显式isset()更清晰。
掌握这三个函数的底层差异,不仅能应对面试,更能避免生产环境中的隐蔽 bug。面试官真正想考察的,不是你能不能背出返回值表格,而是你是否理解 PHP 类型系统与 Zend 引擎的设计哲学。
未经允许不得转载:任鹏个人博客 » PHP 面试精讲:isset、empty、is_null 的底层差异与面试连环问

