Enums em PHP 8.1
Na versão 8.1 do PHP foi introduzido os enums, um recurso já presente em outras linguagens e bastante aguardado no PHP. Os enums nos permite criar uma estrutura parecida com uma classe, mas que armazena somente um conjunto de valores pré-estabelecidos. Antes dele era comum utilizarmos classes com constantes publicas como se fossem enums, mas esta abordagem traz alguns efeitos que podem não ser interessante.
Vamos a um exemplo que talvez você já tenha feito algo parecido, temos algum atributo ou parâmetro de um método ou função que precisa ser limitado a algum conjunto de valores, então criamos uma classe com as constantes destes valores que iremos aceitar e os utilizamos nos locais desejados.
declare(strict_types=1);
class Turno{
public const MANHA = 'MANHA';
public const TARDE = 'TARDE';
public const NOITE = 'NOITE';
}
//--------
// executa.php
function cadastrarDisciplina(string $nome, string $turno){
// faz alguma coisa
echo $nome . ' - ' . $turno . PHP_EOL;
}
cadastrarDisciplina('PHP Básico', Turno::NOITE);
Ao tipar o parâmetro de uma função devemos tipá-lo como string que é o valor contido nas constantes da classe. Desta forma o método não está validando que o valor passado recebe realmente um dos três valores do conjunto de valores válidos, mas somente um string, o que pode ser facilmente burlado.
cadastrarDisciplina('PHP Básico', 'MADRUGADA');
A chamada de função acima é válida e não irá gerar um erro no PHP, mas certamente irá gerar um erro de lógica em seu programa.
Outro problema é que cada um dos valores constantes é um string e pode ser manipulado como uma, podendo ser por exemplo concatenado.
$turno = Turno::MANHA . ' cedo!';
var_dump($turno);
//saída: string(11) "MANHA cedo!"
Esse tipo de problema pode ocasionar bugs difíceis de encontrar. Então utilizando enums isto fica um pouco melhor.
Usando Enums
enum Turno{
case MANHA;
case TARDE;
case NOITE;
}
Declaramos um enum da mesma forma de uma classe, mas utilizando a palavra chave enum, e cada valor do conjunto de valores válidos declaramos utilizando a declaração case
.
Vamos ao exemplo anterior, mas agora com uma enumeração.
function cadastrarDisciplina(string $nome, Turno $turno){
// faz alguma coisa
echo $nome . ' - ' . $turno->name . PHP_EOL;
}
cadastrarDisciplina('PHP Básico', Turno::NOITE);
Se tentarmos agora passar um valor que não for do tipo enum Turno
ele irá gerar um erro.
cadastrarDisciplina('PHP Básico', 'MADRUGADA');
// Erro gerado
//
// Fatal error: Uncaught TypeError: cadastrarDisciplina(): Argument #2 ($turno) must be of type Turno, string given, called in /application/index.php on line 12 and defined in /application/index.php:7
// Stack trace:
// #0 /application/index.php(12): cadastrarDisciplina('PHP B\xC3\xA1sico', 'MADRUGADA')
// #1 {main}
// thrown in /application/index.php on line 7
Como vemos foi gerado um erro informando que o segundo argumento deve ser um Turno e foi passada uma string.
Agora ao tentar concatenar um dos valores do enum irá gerar um erro.
$turno = Turno::MANHA . ' cedo!';
// Erro gerado
//
//Fatal error: Uncaught Error: Object of class Turno could not be converted to string in /application/index.php:14
Isso ocorre porque cada um dos valores do enum é “objeto” do tipo.
$a = Turno::NOITE;
$b = Turno::NOITE;
echo $a === $b; // true
echo $a instanceof Turno; // true
Caso necessitarmos obter nome do valor do enum como string podemos utilizar a propriedade name
.
var_dump( Turno::TARDE->name );
// saída
// string(5) "TARDE"
Por padrão uma enumeração não tem valores escalares, que podem ser inseridos em um banco de dados por exemplo. Mas podemos facilmente defini-los na criação da enum simplesmente definindo o tipo de dado junto a declaração do nome do enum (Turno:string
) e atribuindo o valor escalar correspondente na declaração case
. Lembrando que estes valores devem ser únicos.
enum Turno:string{
case MANHA = 'Manhã';
case TARDE = 'Tarde';
case NOITE = 'Noite';
}
Para acessar o valor escalar de um enum basta utilizar o atributo value
echo Turno::TARDE->name . PHP_EOL; // TARDE
echo Turno::TARDE->value . PHP_EOL; // Tarde
Para obter uma lista de todos os valores de uma enumeração podemos chamar o método cases
, que irá retornar um array contento todos os valores da enumeração.
var_dump( Turno::cases());
// Saída
// array(3) {
// [0]=>
// enum(Turno::MANHA)
// [1]=>
// enum(Turno::TARDE)
// [2]=>
// enum(Turno::NOITE)
// }
Caso seja necessário transformar um valor escalar em um enum, podemos utilizar o método from
passando como argumento o valor escalara e ele irá retornar o valor enum.
$turno = Turno::from('Manhã');
var_dump($turno);
// Saída
// enum(Turno::MANHA)
Podemos também definir métodos dentro de um enumeração, para isso criamos um método como se fosse em uma classe normal acessando o valor de instancia da enumeração através do $this
se necessário.
enum Turno:string{
case MANHA = 'Manhã';
case TARDE = 'Tarde';
case NOITE = 'Noite';
public function saudacao(): string
{
return match($this) {
Turno::MANHA => 'Bom dia!',
Turno::TARDE => 'Boa Tarde!',
Turno::NOITE => 'Boa Noite!',
};
}
}
Então podemos chamar o método normalmente.
$turno = Turno::TARDE;
echo $turno->saudacao();
Bom era isso, enumerações são um boa forma de manter seu código com os dados mais integros e legíveis. Outros exemplos e mais detalhes podem ser visto na própria documentação do PHP.
T++.