PHP8.1新特性之Enumerations(枚举)
我是温馨,一名PHPer
文档:https://www.php.net/manual/zh/language.enumerations.php
枚举,或称 “Enum”,能够让开发者自定义类型为一系列可能的离散值中的一个。 在定义领域模型中很有用,它能够“隔离无效状态”(making invalid states unrepresentable)。
在 PHP 中, 枚举是一种特殊类型的对象。Enum 本身是一个类(Class), 它的各种条目(case)是这个类的单例对象,意味着也是个有效对象 —— 包括类型的检测,能用对象的地方,也可以用它。
枚举基础
enum
是一个限定类,需以enum
关键字开头,后面跟可选的string|int
。
枚举定义
一个枚举可以定义零个或多个case
,且没有最大数量限制。
<?php
// 不初始化直接定义
enum Status {
case Start;
}
// 初始化赋值
enum Status:int {
case Start = 1;
}
// 错误案例,若初始化值,
// 则必须指定枚举类型的变量类型
enum Status {
case Start = 1;
}
enum的基础操作
// 定义枚举
enum Status:int {
case Start = 1;
case End = 2;
}
// 使用枚举
// 获取枚举元素的值
echo Status::Start->value; // 1
// 获取枚举元素的key
echo Status::Start->name; // Start
// 也可以对家对象来操作
$obj = Status::Start;
枚举类型不能被实例化,也没有构造函数。若使用new去实例化,则会报致命错误。
回退枚举,通过值来获取枚举实例
回退枚举仅能回退到 int
或 string
里的一种类型, 且同时仅支持使用一种类型(就是说,不能联合 int|string
)。 回退条目必须是唯一的;两个回退条目不能有相同的标量。
回退枚举实现了内置的BackedEnum interface
,暴露两个额外的方法:
1)from(int|string): self
能够根据标量返回对应的枚举条目。 如果找不到该值,会抛出ValueError
。主要用于输入标量为可信的情况,使用一个不存在的枚举值,可以考虑为需终止应用的错误。
2)tryFrom(int|string): ?self
能够根据标量返回对应的枚举条目。 如果找不到该值,会返回 null
。 主要用于输入标量不可信的情况,调用者需要自己实现默认值的逻辑或错误的处理。
通过 from 来获取枚举类
<?php
enum Status:int {
case Start = 1;
case End = 2;
}
// 使用from通过值来获取枚举类
print_r(Status::from(1));
// 使用不存在的值获取枚举类
print_r(Status::from(404));
// Fatal error: Uncaught ValueError: 404 is not a valid backing value for enum "Status"
通过 tryFrom 来获取枚举类
<?php
var_dump(Status::tryFrom(404)); // NULL
定义枚举方法
枚举(包括纯粹枚举、回退枚举)还能包含方法, 也能实现 interface。 如果 Enum 实现了 interface,则其中的条目也能接受 interface 的类型检测。
<?php
enum Status:int {
case Start = 1;
case End = 2;
// 枚举中定义方法
public function test()
{
// match php8新特性
return match ($this) {
self::Start => '开始状态',
self::End => '结束状态',
};
}
}
// 调用枚举方法
echo Status::Start->test(); // 开始状态
echo Status::End->test(); // 结束状态
枚举中实现接口
<?php
interface TestInterface
{
public function cry();
}
interface DemoInterface
{
public function say();
}
enum Status: int implements TestInterface, DemoInterface
{
case Start = 1;
case End = 2;
public function cry()
{
return self::Start->name;
}
public function say()
{
return match ($this) {
self::Start => '开始状态',
self::End => '结束状态',
};
}
}
echo Status::Start->cry();
枚举使用trait
枚举也能使用 trait,行为和 class 一样。 留意在枚举中 use
trait 不允许包含属性。 只能包含方法、静态方法。 包含属性的 trait 会导致 fatal 错误。
<?php
trait Test
{
public function test($_this)
{
return match ($_this) {
$_this::Start => '开始状态',
$_this::End => '结束状态',
};
}
}
enum Status: int
{
use Test;
case Start = 1;
case End = 2;
public function getStatus()
{
// 调用trait中定义的方法
return $this->test($this);
}
}
echo Status::Start->getStatus();
echo Status::End->getStatus();
判断一个枚举是否存在
enum_exists
判断一个枚举是否存在
<?php
enum Status: int
{
case Start = 1;
case End = 2;
}
var_dump(enum_exists('Status'));
枚举序列化
枚举的序列化不同于对象。 尤其是它们有新的序列化代码: "E"
,指示了 enum 条目名称。
<?php
enum Status: int
{
case Start = 1;
case End = 2;
}
echo serialize(Status::End);
// E:10:"Status:End";
枚举和对象的差异
尽管 enum 基于类和对象,但它们不完全支持对象相关的所有功能。 尤其是枚举条目不能有状态。
枚举的特性
1)禁止构造、析构函数。
2)不支持继承。无法 extend 一个 enum。
3)不支持静态属性和对象属性。
4)由于枚举条目是单例对象,所以不支持对象复制
5)不能使用魔术方法
与对象相同的功能
1)Public、private、protected 方法、静态方法、常量。
2)enum 可以 implement 任意数量的 interface。
3)枚举和它的条目都可以附加注解。
4)常量 __CLASS__
和 __FUNCTION__
的功能和平时无差别