默认情况下,枚举值没有标量等效值。它们只是单例对象。但是,在许多情况下,枚举值需要能够与数据库或类似数据存储进行双向转换,因此定义一个内置的标量(因此可以轻松序列化)等效值对于应用程序来说非常有用。
要为枚举定义标量等效值,语法如下:
<?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()
方法会导致致命错误。