本文目录导读:

在PHP中,空安全操作符(Nullsafe Operator)是PHP 8.0引入的一个特性,语法为 ?->。
它允许你在链式调用对象方法或属性时,如果中间某个环节返回 null,整个表达式会短路并返回 null,而不会抛出错误,也无需使用多层 if 检查。
核心语法
$object?->property?->method();
$object为null,则整个表达式返回null。$object不是null但$object->property是null,则后续的->method()不会执行,整个表达式返回null。
实际例子对比
旧写法(繁琐)
$country = null;
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->country;
}
}
新写法(简洁)
$country = $user?->getAddress()?->country;
主要场景
链式调用方法
$order?->getCustomer()?->getProfile()?->getAvatar();
访问属性
$user?->profile?->bio;
数组偏移(注意:不支持数组,只针对对象属性/方法)
// 错误:$array?->key 会语法错误 // 应用 $array['key'] ?? null $value = $array['key'] ?? null;
重要注意事项
只处理 null,不处理 false 或 0
$obj = new stdClass(); $obj->flag = false; // 下面不会短路,还是会尝试调用 ->someMethod() $result = $obj->flag?->someMethod(); // 会报错,因为 false 不是 null
不适用于 isset() 检查
空安全操作符不会检查属性是否已定义(isset),它只检查是否为 null。
$obj = new stdClass(); // $obj->name 未定义,会直接报错,而不是返回 null $name = $obj->name?->toString();
正确的做法是需要先 isset 或使用 :
$name = $obj->name ?? 'default';
不能用于写操作(赋值)
$obj?->name = 'John'; // 语法错误(除非PHP 8.0+ 某些情况,但不建议)
不能用于数组键访问
$array?->key; // 错误
与 (null合并操作符)的区别
| 操作符 | 用途 | 示例 |
|---|---|---|
?-> |
链式对象调用,如果为 null 则短路 | $a?->b 返回 null 或值 |
| 存在且不为 null 时返回自身,否则返回默认值 | $a ?? 'default' |
它们可以结合使用:
$result = $user?->getProfile()?->getName() ?? 'Guest';
实际应用示例(用户/订单场景)
假设有 User、Order、Address 三个类:
class User {
public ?Order $order;
public function getOrder(): ?Order { return $this->order; }
}
class Order {
public ?Address $address;
public function getAddress(): ?Address { return $this->address; }
}
class Address {
public string $city;
}
// 使用空安全操作符
$city = $user?->getOrder()?->getAddress()?->city;
// 等价于传统写法
$city = null;
if ($user !== null) {
$order = $user->getOrder();
if ($order !== null) {
$address = $order->getAddress();
if ($address !== null) {
$city = $address->city;
}
}
}
?->是数组和对象链式访问的“短路”机制。- 它专为对象设计,不能用于数组或函数返回值(函数返回值需要先赋值给变量再检查)。
- 它只处理
null,不处理false或未定义属性。 - 如果链中某步骤为
null,后续不会执行,整个表达式返回null。 - 非常适合API返回数据、ORM关联查询等场景,能大幅简化代码。
如果你的PHP版本低于8.0,需要先升级才能使用此操作符。