Por omisión, los Casos Enumerados no tienen equivalente escalar. Son simplemente objetos singleton. Sin embargo, hay amplios casos en los que un Caso Enumerado necesita poder hacer un viaje de ida y vuelta a una base de datos o un almacén de datos similar, por lo que tener un equivalente escalar integrado (y por lo tanto trivialmente serializable) definido intrínsecamente es útil.
Para definir un equivalente escalar para una Enumeración, la sintaxis es la siguiente:
<?php
enum Suit: string
{
case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';
}
?>
Un caso que tiene un equivalente escalar se denomina Caso Respaldado, ya que está "respaldado" por un valor más simple. Una enumeración que contiene todos los Casos Respaldados se denomina "Enumeración Respaldada". Una Enumeración Respaldada solo puede contener Casos Respaldados. Una Enumeración Pura solo puede contener Casos Puros.
Una Enumeración Respaldada puede estar respaldada por tipos de int
o string
,
y una enumeración dada admite solo un tipo a la vez (es decir, no hay unión de int|string
).
Si una enumeración está marcada como que tiene un equivalente escalar, entonces todos los casos deben tener un equivalente
escalar único definido explícitamente. No hay equivalentes escalares generados automáticamente
(por ejemplo, enteros secuenciales). Los casos respaldados deben ser únicos; dos casos de enumeración respaldados no pueden
tener el mismo equivalente escalar. Sin embargo, una constante puede referirse a un caso, creando efectivamente
un alias. Ver Constantes de enumeración.
Los valores equivalentes pueden ser una expresión escalar constante.
Antes de PHP 8.2.0, los valores equivalentes debían ser literales o expresiones literales.
Esto significa que las constantes y expresiones constantes no estaban admitidas.
Es decir, 1 + 1
estaba permitido, pero 1 + SOME_CONST
no.
Los Casos Respaldados tienen una propiedad adicional de solo lectura, value
, que es el valor
especificado en la definición.
<?php
print Suit::Clubs->value;
// Imprime "C"
?>
Para hacer cumplir la propiedad value
como de solo lectura, una variable no puede
ser asignada como referencia a ella. Es decir, lo siguiente genera un error:
<?php
$suit = Suit::Clubs;
$ref = &$suit->value;
// Error: No se puede obtener una referencia a la propiedad Suit::$value
?>
Las enumeraciones respaldadas implementan una interfaz interna BackedEnum, que expone dos métodos adicionales:
from(int|string): self
tomará un escalar y devolverá el Caso de Enumeración correspondiente.
Si no se encuentra ninguno, lanzará un ValueError. Esto es principalmente
útil en casos donde el escalar de entrada es confiable y un valor de enumeración faltante debería ser
considerado un error que detiene la aplicación.
tryFrom(int|string): ?self
tomará un escalar y devolverá el
Caso de Enumeración correspondiente. Si no se encuentra ninguno, devolverá null
.
Esto es principalmente útil en casos donde el escalar de entrada no es confiable y el llamador quiere
implementar su propia lógica de manejo de errores o valores por omisión.
Los métodos from()
y tryFrom()
siguen las reglas estándar
de tipado débil/fuerte. En modo de tipado débil, pasar un entero o string es admisible
y el sistema coercionará el valor en consecuencia. Pasar un float también funcionará y será
coercionado. En modo de tipado estricto, pasar un entero a from()
en una
enumeración respaldada por string (o viceversa) resultará en un TypeError,
al igual que un float en todas las circunstancias. Todos los demás tipos de parámetros lanzarán un TypeError
en ambos modos.
<?php
$record = get_stuff_from_database($id);
print $record['suit'];
$suit = Suit::from($record['suit']);
// Datos no válidos lanzan un ValueError: "X" no es un valor escalar válido para la enumeración "Suit"
print $suit->value;
$suit = Suit::tryFrom('A') ?? Suit::Spades;
// Datos no válidos devuelven null, por lo que se usa Suit::Spades en su lugar.
print $suit->value;
?>
Definir manualmente un método from()
o tryFrom()
en una Enumeración Respaldada resultará en un error fatal.