Elvis 还活着:PHP 中 short-ternary 与 null coalescing 的比较

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

谁是 Elvis ?他和 PHP 有什么关系?

\n\n

如果你写过 PHP,你很可能在别人的代码中见过这种奇怪的写法:$name ?: 'Guest' 或 $name ?? 'Guest'。初看之下,它们似乎一样。但实际上,这两个运算符隐藏着完全不同的机制,要么能拯救你的代码,要么会带来麻烦。

\n\n

在 Stack Overflow 上,"PHP 短三元(Elvis)运算符 vs 空合并运算符" 这个问题已经获得了数万次浏览。这绝非偶然。开发者们会搞混、犯错,然后花很长时间排查错误。让我们最终搞清楚谁是谁,别再猜测了。

\n\n

在本文中,我们不仅仅列出差异。我们将深入 PHP 的 底层,审视真实的生产案例,并理解何时该使用哪个运算符。开始吧!

\n\n

快速入门:它们到底是什么?

\n\n

三元运算符(经典)

\n

首先,回顾一下基础。三元运算符是 if-else 的缩写形式:

\n\n
$age = 20;\n$status = ($age >= 18) ? 'Adult' : 'Child';\n// $status = 'Adult'
\n\n

很简单:如果条件为真,取第一个值;否则取第二个。

\n\n

短三元(即 Elvis 运算符)— ?:

\n

这是当你检查变量是否为“真值”并想使用其值时的快捷方式:

\n\n
$name = 'Alexey';\n$greeting = $name ?: 'Guest';\n// $greeting = 'Alexey'\n\n$name = '';\n$greeting = $name ?: 'Guest';\n// $greeting = 'Guest'
\n\n

它的工作原理是:如果 $name 计算为 true,则取 $name。否则,取 "Guest"。

\n\n

空合并运算符 — ??

\n

它出现在 PHP 7.0 中,并迅速成为开发者的最爱:

\n\n
$name = 'Alexey';\n$greeting = $name ?? 'Guest';\n// $greeting = 'Alexey'\n\n$name = null;\n$greeting = $name ?? 'Guest';\n// $greeting = 'Guest'
\n\n

与 Elvis 的区别:检查 仅针对 null,而不是广义上的“假值”。

\n\n

主要区别:什么被认为是“空的”?

\n\n

这就是有趣的地方。让我们看看不同 $value 值下的对比表:

\n\n
$value = false;\necho $value ?: 'default'; // 'default' (false 是 "假值")\necho $value ?? 'default'; // false (false 不是 null)\n\n$value = 0;\necho $value ?: 'default'; // 'default' (0 是 "假值")\necho $value ?? 'default'; // 0 (0 不是 null)\n\n$value = '';\necho $value ?: 'default'; // 'default' (空字符串是 "假值")\necho $value ?? 'default'; // '' (空字符串不是 null)\n\n$value = [];\necho $value ?: 'default'; // 'default' (空数组是 "假值")\necho $value ?? 'default'; // [] (空数组不是 null)\n\n$value = '0';\necho $value ?: 'default'; // 'default' (字符串 "0" 是 "假值"!)\necho $value ?? 'default'; // '0' (字符串 "0" 不是 null)
\n\n

看到区别了吗?Elvis 执行真值/假值检查,而空合并是严格检查变量是否已定义且不为 null。

\n\n

底层原理:在引擎级别如何工作

\n\n

让我们看看 PHP 的源代码(好吧,差不多)。如果你曾经从源码编译过 PHP,你会知道这两个运算符都在解析阶段处理。

\n\n

短三元(?:):

\n

实际上,它是语法糖。$a ?: $b 变成 $a ? $a : $b。但有一个细微差别:PHP 不会对 $a 求值两次。它会将结果保存在一个临时变量中。这对于带有副作用的函数很重要:

\n\n
function getData() {\n    echo "Function called!\\n";\n    return rand(0, 1) ? 'data' : '';\n}\n\n// Elvis 只调用函数一次\n$result = getData() ?: 'default';\n// "Function called!" — 一次
\n\n

如果 PHP 对 $a 求值两次,

博客

书籍推荐