封装 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 协议》,转载必须注明作者和本文链接
关于 LearnKu
延申开去讲,管理一个团队是需要 Java 一般从语言层面的约束的,但是像 PHP 一般自由的团队,可能会更有创造力。
laravel 中 默默认就有Optional
捉个虫,其实 python 是强类型语言 :wink:
Laravel本来就有Optional的实现吧
另外,如果写一篇文章来介绍 Laravel 中 Optional 的使用,不是太枯燥了嘛。所以这篇文章主要说的是,如何判空、不同做法之间的区别,以及如何自行封装(或者你说借鉴 Java 也行)。
phpstorm 支持泛型注释
你说的 ide 提示只需要稍微改动一下就可以了
Optional 示例
User
Conn
看博主的文章学到了, 看评论区更是学到了 :+1: