php ??= 是空合并赋值运算符,仅当左侧变量未定义或为 null 时才赋值;它不改变 0、false、'' 等假值,等价于 $a = $a ?? $b,且要求左操作数为可写变量。

PHP ??= 运算符只在左侧为 null 时才赋值
??= 是 PHP 7.4 引入的空合并赋值运算符,它不是“只要左边假就赋值”,而是严格判断左侧变量是否 未定义或值为 null。这和 ?:=(不存在)或 ||=(逻辑或赋值)完全不同。
常见误用是把它当成“默认值兜底”万能写法,结果发现 0、false、'' 这些值没被覆盖——这恰恰是它设计的本意。
- 等价于:
$a = $a ?? $b;,仅当$a为null或未声明时,才把$b赋给$a - 如果
$a = 0;,执行$a ??= 42;后,$a还是0,不会变成42 - 如果
$a根本没定义,$a ??= 42;会声明并赋值$a = 42;
??= 和 +=、.= 等复合赋值运算符行为一致
它和 +=、.= 一样,是语法糖,但有明确的左操作数约束:左侧必须是可写变量(lvalue),不能是函数调用、数组元素访问(除非已确保存在)、对象属性(无魔术方法时)等。
- ✅ 正确:
$config['timeout'] ??= 30;(前提是$config已存在且为数组) - ❌ 报错:
$_GET['id'] ??= 1;→Fatal error: Cannot use assign-op operators with overloaded objects nor string offsets - ❌ 报错:
foo() ??= 'bar';→ “无法对函数返回值使用赋值运算符” - ⚠️ 注意:
$obj->prop ??= 'val';在$obj无该属性且未定义__set()时,会触发Notice: Undefined property,但仍会赋值成功(PHP 8.0+ 改进为静默)
别在 foreach 循环里对 $item ??= ... 抱有幻想
很多人想用 ??= 初始化循环中的临时变量,比如 foreach ($rows as $row) { $row['status'] ??= 'pending'; }。这看似合理,但实际效果取决于 $rows 的结构:
- 如果
$row是引用(foreach ($rows as &$row)),则修改生效;否则只是复制后修改,原数组不变 - 如果
$row是对象,$row->status ??= 'pending'可能触发__get/__set,行为不可控 - 更安全的写法是显式判断:
if (!isset($row['status'])) $row['status'] = 'pending';,语义清晰,兼容所有 PHP 版本
和 null 合并运算符 ?? 配合使用时要注意求值顺序
??= 的右操作数是惰性求值的——只有左侧为 null 时才会执行右侧表达式。这点常被忽略,尤其当右侧含函数调用时。
function log_and_get_default() {
error_log('default used');
return 'fallback';
}
$config['host'] ??= log_and_get_default();
上面代码中,log_and_get_default() 只有在 $config['host'] 为 null 或未定义时才执行。但如果写成 $config['host'] = $config['host'] ?? log_and_get_default();,右侧表达式每次都会执行(因为 ?? 是普通运算符,不带赋值语义),性能和副作用都不同。
真正容易被绕晕的是嵌套场景:$a['b']['c'] ??= 1 要求 $a 和 $a['b'] 都已存在且为数组,否则报 Warning: Undefined array key。这种情况下,先用 ?? 安全取值再赋值,往往比硬上 ??= 更稳妥。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











