PHP 面试精讲:isset、empty、is_null 的底层差异与面试连环问

在 PHP 面试中,isset()empty()is_null() 这三个函数几乎逢面必问。大多数候选人都能说出“一个判断是否设置、一个判断是否为空、一个判断是否为 null”这样的表面答案。但当面试官继续追问“它们对 0'0'''nullfalse 分别返回什么”“为什么 isset() 不能用于表达式”“empty() 的底层实现是怎样的”时,能完整答对的人并不多。

本文将从语言底层实现出发,逐一拆解这三个函数的本质差异,并整理出面试中常见的连环追问与标准答案。

一、三个函数的本质定位

先给出最核心的结论:

  • isset() 是语言结构(language construct),不是函数。它检查变量是否已声明且值不为 null
  • empty() 也是语言结构。它检查变量是否“为空”,而“空”的定义由 PHP 内核的 zend_is_true 逻辑反向决定。
  • is_null() 是真正的函数。它只做一件事:判断值是否严格等于 null

理解“语言结构 vs 函数”的区别非常重要,因为语言结构由编译器直接处理,不能被可变函数调用,也不能被 array_map 等回调直接使用。

二、isset 的底层行为

isset() 在 Zend 引擎中对应 ZEND_ISSET_ISEMPTY_VAR 操作码。它的判断逻辑是:

  1. 变量在符号表中不存在 → 返回 false
  2. 变量存在但值为 null → 返回 false
  3. 其他任何值,包括 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"(字符串零)
  • null
  • false
  • [](空数组)

注意两个容易踩坑的点:

  1. "0" 被认为是空的。这是 PHP 的历史遗留设计,在判断表单输入时经常导致意外。
  2. 未定义的变量使用 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 在布尔上下文统一处理的结果。虽然社区多次讨论修改,但出于兼容性一直保留。面试中能指出这是历史设计而非逻辑必然,会加分不少。

七、实战建议

  1. 判断变量是否设置用 isset()
  2. 判断是否为 nullis_null()=== null,后者无函数调用开销。
  3. 判断“非空”时慎用 empty(),若业务上 '0' 是合法值,必须用 isset() && $var !== ''
  4. 永远不要依赖 empty() 判断未定义变量来“省事”,显式 isset() 更清晰。

掌握这三个函数的底层差异,不仅能应对面试,更能避免生产环境中的隐蔽 bug。面试官真正想考察的,不是你能不能背出返回值表格,而是你是否理解 PHP 类型系统与 Zend 引擎的设计哲学。

未经允许不得转载:任鹏个人博客 » PHP 面试精讲:isset、empty、is_null 的底层差异与面试连环问

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏