El blog de bCube

[bCube CMS]: ¿Sabías que Php > 8.1 soporta Enums de forma nativa?

Escrito por Daniel Martínez Reina | 13-jul-2023 8:00:00

Las nuevas versiones de Php ofrecen nuevas funcionalidades para poder hacer nuestro código más robusto y más legible. Los Enumerations, o Enums, se introdujeron en Php en la versión 8.0, pero no ha sido hasta la versión 8.1 cuando han incorporado una verdadera funcionalidad, BackedEnum, de la que os hablamos en este nuevo post del blog.

 

Introducción a los Enumerations

Un Enum es similar a una clase y comparte los namespaces, interfaces y traits, pero, a diferencia de ellas, define un nuevo tipo con un nuevo número fijo de posibles valores legales. 

 

 

Como podemos observar, se declaran los posibles valores como Cases dentro del Enum. Cada uno de estos valores se escriben en formato CamelCase, con la primera letra en mayúscula. Esto es importante para poder diferenciar un Enum de una constante de un simple vistazo, ya que en ambos se obtiene su valor en la misma forma :: y puede llevar a confusión. 

 

 

En la versión 8.1 se introducen los Enums escalares y serializables, donde podemos asignar un valor (int o string) a cada uno de los valores posibles de nuestro Enum, los llamados BackedEnum. En el código siguiente vemos que podemos establecer el tipo de dato que va a almacenar nuestro Enum y un valor de ese mismo tipo para cada una de las opciones admitidas por el Enum:

 

 

De esta forma, para poder acceder al valor asignado, utilizaremos la propiedad value de nuestro Enum:

 

 

Funcionalidades básicas de BackedEnum

Los BackedEnum nos brindan la posibilidad de construir un BackedEnum a partir de un valor dado. Para ello, haremos uso de los métodos from(int|string): self y tryFrom(int|string): ?self, métodos similares pero con una pequeña diferencia:

  • from(int|string): self : obtiene un Enum Case a partir de un valor escalar (int o string). Lanzará un \ValueError si el elemento no existe o no se encuentra.
  • tryFrom(int|string): ?self : como el anterior, obtiene un Enum Case a partir de un valor escalar (int o string), pero si el elemento no existe retornará null.

Aquí podemos ver unos ejemplos de uso de ambos métodos:

 

 

Funcionalidades personalizadas

Hasta aquí ya es interesante el poder agrupar en un único lugar qué valores podemos tener de un tipo de dato, o valores aceptados para un campo en concreto sin necesidad de hacer una validación compleja o exhaustiva ya que, con solo capturar una excepción, tenemos el problema resuelto. Pero, ¿qué ocurre si por cada valor en nuestro Enum necesitamos devolver un elemento diferente?

Vamos a poner un caso práctico a modo de ejemplo. Nosotros disponemos de los siguientes tipos de enlaces en nuestro Enum:

 

 

En nuestro modelo de datos, lo almacenamos como un valor entero. Pero, ¿y si necesitamos implementar un endpoint para un cliente y, ellos, en lugar de recibir nuestro entero necesitan obtener un string para cada una de estas posibilidades? Lo más lógico sería pensar en realizar un switch:case en nuestro controlador, o en el mapper de retorno del modelo para controlar las acciones. Pero esto tiene el inconveniente de que, si es utilizado en varias partes de la aplicación, ya tenemos que duplicar código o generar un trait independiente, etc. Usemos la opción que usemos, siempre tendría como inconveniente el tener que buscar estos elementos en varios lugares, con los problemas que esto ocasiona.

Para evitarlos, el BackedEnum permite poder agrupar todo en el mismo lugar, para luego ejecutarlo de forma muy simple:

 

 

Hemos creado el método apiValue(): string, que evalúa que Case tenemos instanciado en nuestro Enum y retorna el valor asociado. Para ello, hacemos uso de la expresión match (introducida en php 8.0). Ahora, para poder transformar un Case de entero a string, solo debemos hacer uso de nuestro método:

 

 

Esto nos retornará el valor del Case External transformado en string, lo que nos brinda infinitas posibilidades y, lo más importante, poder tener todo lo relativo a un mismo Enum ordenado en el mismo lugar. Así, en el caso de necesitar algún cambio, como por ejemplo añadir un nuevo Case, será muy sencillo poder localizar todos los usos, ya que la mayoría de lógica la tenemos agrupada aquí.

 

FPhp > 8.2

Cuando usemos Php 8.2, podremos establecer Cases de Enums o values de Enums directamente en la asignación de propiedades:

 

 

Dentro de un BackedEnum podemos establecer constantes que apunten a un valor de los Enums.

 

 

En la web oficial de Php podemos encontrar más información al respecto.

Daniel Martínez Reina es Desarrollador Fullstack de Bitban Technologies.