?? 运算符专用于判断变量是否为 null 或未定义,仅在此时取右侧值;它不将 0、''、false 等 falsy 值视为“空”,故不同于 ?: 和 isset(),适用于安全获取默认值场景。

PHP ?? 运算符到底怎么用
它不是三元运算符的简写,也不是 isset() 的替代品,而是专门用来处理「变量存在但为 null」和「变量未定义」两种情况的合并判断。核心逻辑是:左边操作数不为 null 且已定义,就取它;否则取右边。
什么时候必须用 ??,而不是 ?: 或 isset()
常见错误是把 ?? 当成 ?: 的语法糖,结果在值为 0、''、false 时出错——?? 不会把这些“falsy 值”当作空,只认 null 和未定义。
-
$name = $_GET['name'] ?? 'guest';—— 安全,即使$_GET['name']不存在或为null都不会报 Notice -
$name = $_GET['name'] ?: 'guest';—— 危险,如果$_GET['name']是''或0,也会回退到'guest' -
$name = isset($_GET['name']) ? $_GET['name'] : 'guest';—— 等价但啰嗦,且多一次函数调用开销
嵌套 ?? 和链式访问的坑
PHP 7.4+ 支持属性或数组键的链式空合并,比如 $user->profile->avatar ?? 'default.png',但注意:只要中间任意一环是 null 或不存在,整个表达式就短路返回右侧值,**不会抛出 Error**(前提是启用了 strict_types=0 默认行为)。
- 如果
$user是null,$user->profile不会触发致命错误,??直接生效 - 但如果
$user是对象,$user->profile是null,而你又写了$user->profile->url,那就会报Trying to get property 'url' of non-object——??只作用于紧邻的左侧操作数,不自动穿透多层 - 安全写法是逐层加
??:($user->profile ?? [])->url ?? 'default.jpg'
和 nullsafe 运算符(?->)混用要注意什么
PHP 8.0 引入了 ?->,它和 ?? 解决的是不同问题:?-> 防止调用空对象方法/属性报错,?? 提供默认值。两者可以配合,但顺序不能反。
立即学习“PHP免费学习笔记(深入)”;
- ✅ 正确:
$user?->getProfile()?->getAvatar() ?? 'anon.svg'—— 先安全调用,再合并默认值 - ❌ 错误:
($user?->getProfile() ?? new Profile())->getAvatar()—— 如果$user为 null,?->返回 null,??生效;但若getProfile()返回 null,??也生效,可你未必想 new 一个新对象 - 兼容性提醒:
?->是 PHP 8.0+,??是 PHP 7.0+,老项目只用??更稳妥
真正容易被忽略的是:当变量来自用户输入或外部数据(比如 JSON 解码后字段缺失),?? 能消 Notice,但掩盖了数据结构不一致的问题。上线前最好用类型声明或验证确认关键字段是否存在,而不是全靠 ?? 喂默认值兜底。










