Por padrão, os Casos não possuem um equivalente escalar. Eles são apenas objetos singleton. No entanto, existem muitos casos em que um Caso Enumerado precisa ser capaz de fazer fazer uma conversão de ida e volta para um banco de dados ou um armazenamento de dados semelhante, então ter um escalar embutido (e, portanto, trivialmente serializável) equivalente definido intrinsecamente é útil.
Para definir um equivalente escalar para uma Enumeração, a sintaxe é a seguinte:
<?php
enum Naipe: string
{
case Copas = 'C';
case Ouros = 'O';
case Paus = 'P';
case Espadas = 'E';
}
?>
Um caso que possui um equivalente escalar é chamado de Backed Case, sendo "Backed" no sentido de lastreado, suportado, por um valor mais simples. Uma Enum que possui todos Casos Lastreados é chamada Backed Enum. Uma Backed Enum pode conter apenas Backed Case. Uma Enum Pura pode conter apenas Casos Puros.
Uma Backed Enum pode associar valores de tipos int
ou string
,
e uma determinada enumeração suporta apenas um único tipo de cada vez (isto é, sem união de int|string
).
Se uma enumeração for marcada como tendo um equivalente escalar, então todos os casos devem possuir um escalar equivalente
único definido explicitamente. Não existem equivalentes escalares gerados automaticamente
(p. ex.: inteiros sequenciais). Casos lastreados devem ser únicos; dois casos enum lastreados não podem
ter o mesmo equivalente escalar. No entanto, uma constante pode se referir a um caso, efetivamente
criando um apelido. Veja Constantes de enumeração.
Valores equivalentes devem ser literais ou expressões literais. Constantes e expressões constantes
não são suportadas. Isto é, 1 + 1
é permitido, mas 1 + SOME_CONST
não é.
Backed Cases possuem uma propriedade somente leitura adicional, value
, que é o valor
especificado na definição.
<?php
print Naipe::Paus->value;
// Imprime "P"
?>
Para impor a propriedade value
como somente leitura, uma variável não pode
ser atribuída como uma referência para ela. Isto é, o seguinte lança um erro:
<?php
$naipe = Naipe::Paus;
$ref = &$naipe->value;
// Error: Cannot acquire reference to property Naipe::$value
?>
Backed Enums implementam uma interface interna BackedEnum, que expõe dois métodos adicionais:
from(int|string): self
recebe uma escalar e retornará o Caso Enum
correspondente. Se um não for encontrado, ela lançará um ValueError. Isso é útil
principalmente nas situações somente valores previstos são permitidos e um valor enum ausente deve ser
considerado um erro de interrupção de aplicação.
tryFrom(int|string): ?self
recebe uma escalar e retornará o
Caso Enum correspondente. Se um não for encontrado, ela retornará null
.
Isso é útil principalmente em casos onde o escalar de entrada não é confiável e o chamador quer
implementar sua própria lógica de manipulação de erros ou de valor padrão.
Os métodos from()
e tryFrom()
seguem as regras
padrão de tipagem fraca/forte. No modo de tipagem fraca, passar um inteiro ou string é aceitável
e o sistema irá coagir o valor de acordo. Passar um float também irá funcionar e será
convertido. No modo de tipagem estrita, passar um inteiro para from()
em uma
enum associada a strings (ou vice-versa) irá resultar em um TypeError,
assim como um float irá lançar um erro em todas as circunstâncias. Todos os outros tipos de parâmetro lançarão um TypeError
em ambos os modos.
<?php
$registro = obter_coisas_do_banco_de_dados($id);
print $registro['naipe'];
$naipe = Naipe::from($registro['naipe']);
// Dados inválidos lançam um ValueError: "X" is not a valid scalar value for enum "Naipe"
print $naipe->value;
$naipe = Naipe::tryFrom('A') ?? Naipe::Espadas;
// Dados inválidos retornam null, então Naipe::Espadas em seu lugar.
print $naipe->value;
?>
Definir manualmente um método from()
ou tryFrom()
em uma Backed Enum irá resultar em um erro fatal.