PHP8.1新特性之Enumerations(枚举)

作者: 温新

分类: 【PHP基础】

阅读: 5386

时间: 2022-02-20 14:06:36

我是温馨,一名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去实例化,则会报致命错误。

回退枚举,通过值来获取枚举实例

回退枚举仅能回退到 intstring 里的一种类型, 且同时仅支持使用一种类型(就是说,不能联合 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__ 的功能和平时无差别

请登录后再评论