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__ 的功能和平时无差别