Menu

Enum em PHP: backed enums, from(), tryFrom() e cases()

Um enum PHP (8.1+) é um tipo com uma lista fixa de valores: enum Status: string { case Active = 'active'; }. Veja enums puros e backed, ->value e ->name, conversão com from() e tryFrom(), como listar os casos com cases(), métodos, constantes, interfaces e enums no match.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Um enum PHP (PHP 8.1+) define um tipo com um conjunto fixo de valores possíveis, os seus casos: enum Status { case Active; case Banned; }. Você usa um caso como Status::Active, e um parâmetro com o tipo Status não aceita mais nada. Um backed enum, enum Status: string, também dá a cada caso um valor que você pode guardar e converter de volta com Status::from().

Antes dos enums, a mesma coisa era uma lista de constantes string, e nada impedia que um erro de digitação como 'actve' chegasse ao banco de dados. Com Status como tipo do parâmetro, só os três casos podem ser passados.

Enums puros e backed enums

Um enum puro tem casos que são só nomes. Um backed enum declara um tipo depois do nome, int ou string, e então cada caso precisa ter um valor único desse tipo. Todo caso tem ->name; só casos backed têm ->value.

Escolha um backed enum sempre que o valor sair do programa: uma coluna do banco, uma URL, um campo de formulário, JSON. Escolha um enum puro para valores que só existem dentro do código, como o estado de um parser.

Converter um valor com from() e tryFrom()

Backed enums ganham dois métodos estáticos para transformar um valor guardado de volta num caso. from() lança um ValueError para um valor desconhecido; tryFrom() retorna null, o que combina bem com ?? para um padrão:

Use tryFrom() em qualquer coisa que um usuário enviou, e from() em valores que o seu próprio código escreveu, em que um valor desconhecido significa um bug que você quer descobrir. O argumento segue as regras normais de tipo de parâmetro: num enum int, Priority::from('5') retorna Priority::Normal no modo padrão porque '5' é convertido em 5 antes, Priority::from('5x') é um TypeError, e com declare(strict_types=1) qualquer string é um TypeError. Isso inclui o tryFrom(): Priority::tryFrom('abc') lança um erro em vez de retornar null, então verifique a entrada de formulário para um enum int com filter_var($raw, FILTER_VALIDATE_INT) antes.

Listar todos os casos com cases()

Enum::cases() retorna um array com todos os casos, na ordem em que foram declarados. É assim que você monta um dropdown, valida uma lista ou pega todos os valores com array_column:

Rode, escolha um plano e clique em Choose: o mesmo script roda de novo com $_POST['plan'] preenchido, e o tryFrom() transforma a string enviada de volta num caso de Plan. Um valor forjado como plan=gold dá null, e nenhuma opção fica selecionada.

Métodos, constantes e interfaces em enums

Enums podem ter métodos, métodos estáticos e constantes, e podem implementar interfaces. Dentro de um método, $this é o caso atual, o que torna match ($this) o jeito natural de associar dados a cada caso. O que um enum não pode ter são propriedades: dados por caso vêm de métodos.

Enums no match

O match compara com ===, e um caso de enum só é idêntico a si mesmo, então match e enums combinam. Se você esquecer um caso e esse caso chegar ao match, o PHP lança um UnhandledMatchError em vez de não retornar nada em silêncio:

Veja match para entender como o match difere do switch.

Enums em JSON e como strings

O json_encode() escreve um caso backed como o seu valor. Um enum puro não pode ser codificado, e dar echo em qualquer caso falha, porque um enum é um objeto, não uma string. Imprima ->value ou ->name:

echo Role::Admin; lança um Error ("Object of class Role could not be converted to string"), e enums não podem implementar __toString(). Na volta, o JSON dá uma string simples, então converta-a com from() ou tryFrom() como mostrado. Mais sobre codificação em json_encode.

Erros comuns com enums

Três erros aparecem o tempo todo. Um caso nunca é igual ao seu valor, um caso não pode ser chave de array, e new não funciona num enum:

Se você precisa de um mapa com os próprios casos como chave, use SplObjectStorage ou WeakMap, que aceitam objetos como chaves.

Perguntas frequentes

Como pego o valor de um enum no PHP?

Num backed enum, leia ->value: Status::Active->value é 'active'. Todo caso também tem ->name, o nome do caso como string ('Active'). Um enum puro (sem : string ou : int) só tem ->name.

Qual a diferença entre from() e tryFrom() nos enums do PHP?

Os dois transformam um valor num caso de um backed enum. Status::from('active') retorna o caso ou lança um ValueError quando nenhum caso tem aquele valor; Status::tryFrom('nope') retorna null. Use tryFrom() para entradas do usuário e from() quando um valor inválido for um bug.

Como pego todos os valores de um enum no PHP?

Status::cases() retorna todos os casos na ordem de declaração. Para os valores de um backed enum use array_column(Status::cases(), 'value'), e para os nomes array_column(Status::cases(), 'name').

Qual a diferença entre um enum puro e um backed enum?

Um enum puro (enum Suit { case Hearts; }) tem casos que são só nomes. Um backed enum (enum Suit: string { case Hearts = 'H'; }) dá a cada caso um valor int ou string único, de que você precisa para guardá-lo num banco de dados, colocá-lo num formulário ou JSON e convertê-lo de volta com from() ou tryFrom().

Um enum PHP pode ter métodos?

Sim. Enums podem ter métodos, métodos estáticos e constantes, e podem implementar interfaces. Dentro de um método, $this é o caso atual, então return match ($this) { self::Active => 'green', self::Banned => 'red' }; é um padrão comum. Enums não podem ter propriedades.

Ilustração das linguagens de programação do Coddy

Aprenda a programar com o Coddy

COMEÇAR