默认情况下,枚举成员没有标量等价物。它们只是单例对象。但是,在很多情况下,枚举成员需要能够往返于数据库或类似的数据存储,因此在内部定义一个内置的标量(因此可以轻松序列化)等价物非常有用。
要为枚举定义一个标量等价物,语法如下所示
<?php
enum Suit: string
{
case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';
}
?>
具有标量等价物的成员称为支持底层值的成员,因为它“由”一个更简单的值支持。包含所有支持底层值的成员的枚举称为“支持底层值的枚举”。支持底层值的枚举只能包含支持底层值的成员。纯枚举只能包含纯成员。
支持底层值的枚举可以由 int
或 string
类型支持,并且给定的枚举一次只能支持一种类型(即,不支持 int|string
的联合)。如果枚举被标记为具有标量等价物,则所有成员都必须显式定义唯一的标量等价物。没有自动生成的标量等价物(例如,连续整数)。支持底层值的成员必须是唯一的;两个支持底层值的枚举成员不能具有相同的标量等价物。但是,常量可以引用一个成员,有效地创建一个别名。请参阅 枚举常量。
等价值必须是文字或文字表达式。不支持常量和常量表达式。也就是说,1 + 1
是允许的,但 1 + SOME_CONST
不允许。
支持底层值的成员有一个额外的只读属性 value
,它是定义中指定的值。
<?php
print Suit::Clubs->value;
// 输出 "C"
?>
为了将 value
属性强制为只读,变量不能作为引用分配给它。也就是说,以下操作会抛出错误
<?php
$suit = Suit::Clubs;
$ref = &$suit->value;
// 错误:无法获取属性 Suit::$value 的引用
?>
支持底层值的枚举实现了一个内部 BackedEnum 接口,该接口公开了另外两种方法
from(int|string): self
将获取一个标量并返回相应的枚举成员。如果找不到,它将抛出一个 ValueError。这主要用于输入标量可信且缺少的枚举值应被视为应用程序停止错误的情况。tryFrom(int|string): ?self
将获取一个标量并返回相应的枚举成员。如果找不到,它将返回 null
。这主要用于输入标量不可信且调用方希望实现自己的错误处理或默认值逻辑的情况。from()
和 tryFrom()
方法遵循标准的弱/强类型规则。在弱类型模式下,传递整数或字符串是可以接受的,系统将相应地强制转换值。传递浮点数也将起作用并被强制转换。在严格类型模式下,对字符串支持的枚举传递整数到 from()
(反之亦然)将导致 TypeError,浮点数在所有情况下都会导致 TypeError。在两种模式下,所有其他参数类型都将抛出 TypeError。
<?php
$record = get_stuff_from_database($id);
print $record['suit'];
$suit = Suit::from($record['suit']);
// 无效数据抛出 ValueError:"X" 不是枚举 "Suit" 的有效标量值
print $suit->value;
$suit = Suit::tryFrom('A') ?? Suit::Spades;
// 无效数据返回 null,因此使用 Suit::Spades。
print $suit->value;
?>
在支持底层值的枚举上手动定义 from()
或 tryFrom()
方法将导致致命错误。