枚举类型,简称“枚举”,是一种对命名值进行分类的数据类型。可以使用枚举代替硬编码字符串来表示,例如,以结构化和类型化的方式表示博客文章的状态。
PHP 8.1之前没有自带枚举类型,在8.1之前,如果我们要使用枚举类型,一个最佳实践是使用myclabs/php-enum这个扩展包。
在php 8.1里,就有了默认的enum class支持了,但是呢,估计很多人的php版本还是在8.1以下,所有了解一下8.1之前枚举类型方面的实践和原理,也是很有必要的,后续的文章里,我们再专门介绍php 8.1的enum class。
举个栗子:
class Post
{
// Post::$status:draft,published或archived
public function setStatus(PostStatus $status): void
{
$this->status = $status;
}
}
假设我们想着在存Post数据的时候,设置post实例的状态,这是很经典、很常见的日常操作。如果用了myclabs/php-enum包,我们可以这样写:
class PostStatus extends Enum
{
const DRAFT = 'draft';
const PUBLISHED = 'published';
const ARCHIVED = 'archived';
}
我们可以像这样直接使用常量值:
class Post
{
public function setStatus(string $status): void
{
$this->status = $status;
}
}
// …
$post->setStatus(PostStatus::DRAFT);
但这会阻止我们进行正确的类型检查,因为任何字符串都可以传递给Post::setStatus(),更好的方法是使用这个库提供的方法:
class PostStatus extends Enum
{
private const DRAFT = 'draft';
private const PUBLISHED = 'published';
private const ARCHIVED = 'archived';
}
$post->setStatus(PostStatus::DRAFT());
虽然表面上好像不存在这个DRAFT()方法,但是它背后通过__callStatic()这个魔术方法,构建了一个PostStatus类的对象,它对应的值就是'draft'。
这样我们可以检查PostStatus的传参类型,并确保其值是“枚举”定义的三种状态之一。
但是,由于它背后是通过__callStatic()来实现,我们的IDE就没法进行静态分析了,在IDE自动完成提示或重构时可能就麻烦一些:

如上所示,IDE 不知道该PostsStatus::DRAFT()方法,我们又不得不通过代码块注释来解决:
/**
* @method static self DRAFT()
* @method static self PUBLISHED()
* @method static self ARCHIVED()
*/
class PostStatus extends Enum
{
private const DRAFT = 'draft';
private const PUBLISHED = 'published';
private const ARCHIVED = 'archived';
}
$post->setStatus(PostStatus::DRAFT());
稍微有些麻烦,对吧,但是也会比直接在class里写很多的const要好不少,我知道很多小伙伴都是这么做的。
当然了,如果你是用的php 8.1,那么现在枚举类型已经默认支持了,而且更简单、更优雅,这个我们后续来讲,了解一下之前版本的一般实践,对于后续理解是有益的。
更好阅读体验,可以到我原站阅读:
我是霹雳神,欢迎到我的技术站点pilishen.com做客,也欢迎到我们的公开群来玩:109256050(公开课@pilishen.com)