php8 ?-> nullsafe 操作符 使用教程

简介

PHP 8 引入了 ?->Nullsafe 操作符),用于简化 null 检查,减少繁琐的 if 语句或 isset() 代码,提高可读性。

?-> Nullsafe 操作符的作用

PHP 7 及以下,访问对象的属性或方法时,如果对象是 null,会导致致命错误 (Fatal error):

$person = null;
echo $person->name; // Fatal error: Uncaught Error: Trying to get property of non-object

解决方案(传统写法):

$person = null;
echo isset($person) ? $person->name : null;

PHP 8 解决方案(?->):

$person = null;
echo $person?->name; // 不会报错,直接返回 null

?-> 基本用法

访问对象的属性
class Person {
    public string $name = "John";
}

$person = new Person();
echo $person?->name; // 输出 "John"

$person = null;
echo $person?->name; // 输出 null,不会报错
访问对象的方法
class User {
    public function getName() {
        return "Alice";
    }
}

$user = new User();
echo $user?->getName(); // 输出 "Alice"

$user = null;
echo $user?->getName(); // 输出 null,不会报错
访问嵌套对象
class Address {
    public string $city = "New York";
}

class Person {
    public ?Address $address = null;
}

$person = new Person();
echo $person->address?->city; // 输出 null,不会报错

$person->address = new Address();
echo $person->address?->city; // 输出 "New York"
?-> 结合数组

不能用于数组索引([]),但可以用于 ArrayAccess 对象

$data = null;
echo $data?['key']; // 语法错误:不能用于数组

解决方案:使用 ArrayAccess 对象

class Collection implements ArrayAccess {
    private array $items = ['name' => 'Alice'];

    public function offsetExists($offset) { return isset($this->items[$offset]); }
    public function offsetGet($offset) { return $this->items[$offset] ?? null; }
    public function offsetSet($offset, $value) { $this->items[$offset] = $value; }
    public function offsetUnset($offset) { unset($this->items[$offset]); }
}

$collection = new Collection();
echo $collection?->offsetGet('name'); // 输出 "Alice"

$collection = null;
echo $collection?->offsetGet('name'); // 输出 null,不会报错
?-> 结合函数返回值
function getUser() {
    return null;
}

echo getUser()?->name; // 输出 null,不会报错
?-> 结合链式调用

PHP 8 允许链式 ?-> 操作,简化复杂的 null 检查:

class Department {
    public ?Person $manager = null;
}

$department = new Department();

// 传统写法
echo isset($department->manager) ? $department->manager->name : null;

// PHP 8 `?->`
echo $department?->manager?->name; // 输出 null,不会报错
?-> 结合赋值

?-> 不能用于赋值,只能用于访问!

$person = null;

// 不能用 `?->` 进行赋值
$person?->name = "John"; // 语法错误

解决方案:

if ($person !== null) {
    $person->name = "John";
}
?-> 不能用于静态方法
class Test {
    public static function hello() {
        return "Hello";
    }
}

echo Test?->hello(); // ❌ 语法错误

静态方法必须用 :: 访问,不支持 ?->

解决方案:

echo isset(Test::hello) ? Test::hello() : null;
?-> 和 ?? 的区别

?-> 用于对象,?? 用于 null 合并

$person = null;

// `?->` 适用于对象
echo $person?->name; // 返回 null

// `??` 适用于变量为空时提供默认值
echo $person?->name ?? "Default Name"; // 输出 "Default Name"
  • ?-> 用于安全访问对象的属性或方法。

  • ?? 用于 null 合并,提供默认值。

帮我看看现在的代码运行时候有问题,/**获取用户信息 * @param int $brandId * @param string $token * @return array */ public static function getThirdUserInfoCurrent(int $brandId, string $token, string $brandCode): array { return grpcCallWithRetry(function() use ($brandId, $token, $brandCode) { $member_client = null; $GetThirdUserInfoCurrentRequest = null; try { $member_config = config("grpc.member_srv"); $member_client = new MemberSrvClient($member_config, ['credentials' => null]); $GetThirdUserInfoCurrentRequest = new GetThirdUserInfoCurrentRequest(); $header = [ 'content-type' => ['application/grpc+proto'], 'te' => ['trailers'], 'user-agent' => ['grpc-php-hyperf/1.0 (hyperf-grpc-client/v2.2.22)'], 'brandid' => [''.$brandId], 'brandcode' => [$brandCode], 'token' => [$token] ]; //调用服务 list($reply, $status) = $member_client->getThirdUserInfoCurrent($GetThirdUserInfoCurrentRequest,$header)->wait(); if(!$reply) { $error = json_encode($header).'。'; if ($status){ $error .= json_encode((array)$status); } throw new \Exception('reply返回为空,$token:'.$token.',status:'.$error); } if(!$status) { $error = json_encode($header).'。'; if(is_object($reply)){ $error .= '。reply:'.json_encode((array)$reply); } throw new \Exception('status返回为空,$token:'.$token.',reply:'.$error); } $errCode = $reply->getCode(); $errMessage = $reply->getMessage(); $requestId = $reply->getRequestId(); if ($errCode != 100) { $error = json_encode($header).'。'; if ($status){ $error .= json_encode((array)$status); } if(is_object($reply)){ $error .= '。reply:'.json_encode((array)$reply); } throw new \Exception('$token:'.$token.',errCode:'.$errCode.',requestId:'.$requestId.',error:'.$errMessage.',status:'.$error); } $object = $reply->getData(); if (!$object) { $error = json_encode($header).'。'; if ($status){ $error .= json_encode((array)$status); } throw new \Exception('errCode:'.$errCode.',requestId:'.$requestId.',error:'.$errMessage.',status:'.$error); } $objects = $object->getUserThirdParty(); $object1 = $object->getUser(); $thirduser = [ "id" => $objects->getId(), "user_id" => $objects->getUserId(), "avatar" => $objects->getAvatar(), "nickname" => $objects->getNicknameEncode() ?json_decode(json_encode(base64_decode($objects->getNicknameEncode()), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE),true): $objects->getBrandCode() . '-' . $objects->getId(), "wx_unionid" => $objects->getUnionId(), "platform" => $objects->getPlatform(), "brand_id" => $objects->getBrandId(), "brand_code" => $objects->getBrandCode(), "sex" => $objects->getSex(), "status" => $objects->getStatus(), ]; if($objects->getPlatform() == 'wechat'){ $thirduser['wx_openid'] = $objects->getOpenid(); } if($objects->getPlatform() == 'alipay'){ $thirduser['ali_openid'] = $objects->getOpenid(); } if(!empty($object1) && !empty($object1->getUsercard())){ $thirduser['usercard'] = $object1->getUsercard(); } if(!empty($object1) && !empty($object1->getGradeId())){ $thirduser['grade_id'] = $object1->getGradeId(); } if(!empty($object1) && !empty($object1->getMobile())){ $thirduser['mobile'] = $object1->getMobile(); } if(!empty($object1) && !empty($object1->getIsStaff())) { $thirduser['is_staff'] = $object1->getIsStaff() ?? 0; $thirduser['staff_no'] = $object1->getStaffNo() ?? ''; $thirduser['staff_alias'] = $object1->getStaffAlias() ?? ''; $thirduser['staff_branch_code'] = $object1->getStaffBranchCode() ?? ''; } return $thirduser; } catch (\Exception $e) { InterfaceLogLogic::add('获取用户登录信息失败,'. $e->getCode() . $e->getMessage(), 'getThirdUserInfoCurrent',$brandId); return []; } finally { if($member_client){ $member_client->close(); unset($member_client); } if($GetThirdUserInfoCurrentRequest){ unset($GetThirdUserInfoCurrentRequest); } } }, 3, 500); // 最多重试3次,基础延迟500ms }
最新发布
09-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值