封装 Optional 对象来判断空值
这篇文档讲述了我们如何来处理代码中的空值(null
),我封装了一个 Optional
的对象来处理空值。
两种处理空值的方法的对比
首先我们来对比一下两种写法, PHP 中传统判断空值的写法。首先,我先创建一个获取用户的函数, 正常的写法去判断是否为空:
function getUser(int $id): ?UserModel
{
return UserModel::find($id);
}
$user = getUser(1);
if ($user === null) {
throw new Exception('The user does not exists.')
}
如果使用 Optional
对象,其写法如下:
function getUser(): ?UserModel
{
// 使用 Optional 对象包裹一层
return Optional::ofNullable(
UserModel::find($id)
);
}
$user = getUser()
// 如果为空,则抛出异常
->ofElseThrow(fn () => new BadRequestException('The user does not exists.'))
->get(); // 如果不会空,则通过 get() 方法获取
这种写法来自 Java,为了解决 Java 中令人头疼的 NPE(空指针异常)。这个
Optional
的做法是来自 Google 的 Guava 工具库,后在 Java8 中被吸收,从语言层面给与支持。
两种写法的深入思考
看上去,第二种写法更加抽象与复杂(即使是在 Java 中,很多开发者也是不习惯使用 Optional
对象的。但是我们要清楚,这种封装要解决的是什么问题:强制开发者判断返回值是否为空 。
第一种写法更加简洁,但是在实际编码中,开发者经常会有意或无意的忽略去检查返回值是否为空。 我封装这个的目的,不是为了推广这种写法,而是来说,针对 null
我们存在不同的处理方法。
一种方法依赖于开发者的习惯,第二种方法从语言层面来进行约束。所以, PHP 开发者核心成员的鸟哥说:其实动态类型的语言,更加考验开发者的能力。 我是这么理解的:弱类型的语言,想要灵活玩转他的灵活性其实很难,不管是 PHP 还是 JavaScript 或是 Python,它给了开发者更多的自由,但如果自由过了火,对大型的团队项目来说就是灾难。
我要强调的是,语言往往不是关键,关键在于开发者本身。用 C 也能写出面向对象的代码,用 Java 也能写出 PHP 的代码,用 PHP 也能写出 Laravel 源码一般的优雅的代码。
这样的实现在 PHP 中是存在代价的,IDE 会丧失了对返回值类型的推断能力。但是在 Java 中,由于泛型的存在,是可以的。
下面评论中有提到可以使用 PHPStorm 的泛型注释,我也试了一下,非常棒。
PHP、Python 这种语言是永远不会去实现泛型的,因为本身就是动态类型语言,支持鸭子类型,故不需要泛型 。
Optional 的简单实现
然后我们简单来实现一下,上文中演示的 Optional 的封装,就 3 个方法:
class Optional
{
private mixed $value;
public function __construct(mixed $value)
{
$this->value = $value;
}
// 如果为空,则抛出异常,否则返回值
public function get(): mixed
{
if ($this->value === null) {
throw new NotSuchElementException();
}
return $this->value;
}
// 构造一个 Optional 的对象,允许为空
public static function ofNullable(mixed $value): self
{
return new self($value);
}
// 如果存在 null,则执行回调函数并抛出异常,否则返回自身实例
public function ofElseThrow(callable $exception): self
{
if ($this->value !== null) {
return $this;
}
throw $exception();
}
}
总结
通过这篇文档,我想说的是,我们不应该只关注语言本身,而是关注语言背后的那些思想,以及所解决的问题。
本作品采用《CC 协议》,转载必须注明作者和本文链接
延申开去讲,管理一个团队是需要 Java 一般从语言层面的约束的,但是像 PHP 一般自由的团队,可能会更有创造力。
laravel 中 默默认就有Optional
捉个虫,其实 python 是强类型语言 :wink:
Laravel本来就有Optional的实现吧
另外,如果写一篇文章来介绍 Laravel 中 Optional 的使用,不是太枯燥了嘛。所以这篇文章主要说的是,如何判空、不同做法之间的区别,以及如何自行封装(或者你说借鉴 Java 也行)。
phpstorm 支持泛型注释
你说的 ide 提示只需要稍微改动一下就可以了
Optional 示例
User
Conn
看博主的文章学到了, 看评论区更是学到了 :+1: