?? 只检测左侧是否为 null,不处理 false、0、'' 或 [];用于安全解包需逐层 ?? 或配合 isset(),PHP 8.0+ 推荐用 ?-> 配合 ?? 处理对象属性。

PHP 本身没有 ?? 以外的空值合并操作符,?? 就是它的 coalesce —— 但很多人用错场景、误判“空”的含义,甚至在对象属性或数组嵌套里硬套它。
为什么 ?? 不等于“只要为空就取右边”
?? 只检测左侧是否为 null,不是 false、0、'' 或 []。这是它和 ?: 的根本区别。
常见错误现象:$name = $user['name'] ?: 'Anonymous'; —— 当 $user['name'] 是 0 或 false,也会触发默认值,但你可能只想处理缺失键。
- 用
??:只关心“是否存在且非null”,适合解包数组/对象属性 - 用
?::实际是“falsy fallback”,语义不同,别混用 - 想真正模拟 SQL 的
COALESCE()(跳过所有 falsy 值)?PHP 没原生支持,得自己写函数
嵌套数组访问时 ?? 会报 Notice: Undefined index
直接写 $data['user']['profile']['email'] ?? 'no@email' 在 $data['user'] 不存在时仍会触发 notice —— ?? 不阻止中间层级的访问错误。
立即学习“PHP免费学习笔记(深入)”;
使用场景:从 API 响应或配置数组中安全取深层字段。
- 正确做法:逐层用
??,如($data['user'] ?? [])['profile'] ?? [])['email'] ?? 'no@email' - 更清晰写法:用
isset()+ 三元,或封装成辅助函数(比如 Laravel 的data_get()) - PHP 8.0+ 可用空安全操作符
?->,但它只适用于对象,不适用于数组
对象属性访问不能直接用 ?? 判断是否可读
$user->name ?? 'N/A' 看似合理,但如果 $user 是 null,会报 Fatal error: Uncaught Error: Attempt to read property "name" on null —— ?? 的左操作数在 PHP 8.0 前不支持空安全求值。
性能 / 兼容性影响:PHP 7.x 必须先判空;PHP 8.0+ 才能用 $user?->name ?? 'N/A'。
- PHP 7.x:必须写成
($user !== null ? $user->name : null) ?? 'N/A'或isset($user->name) ? $user->name : 'N/A' - PHP 8.0+:优先用
$user?->name ?? 'N/A',简洁且安全 - 注意:
?->不会静默忽略访问异常(比如 __get() 抛出 Exception),它只跳过null
真正难的不是记住 ?? 的语法,而是每次写之前想清楚:你要跳过的到底是 null,还是所有 falsy 值?左侧值有没有可能根本不存在(数组键/对象实例)?PHP 不会替你猜语义,它只按规则执行。











