Enums en PHP moderno

Avanzado
PHP
PHP
Actualizado: 19/04/2026

Las enumeraciones fueron introducidas en PHP 8.1 como un ciudadano de primera clase del lenguaje y vinieron a sustituir a los antiguos trucos basados en constantes de clase o cadenas mágicas. Un enum declara un conjunto cerrado de valores posibles y ofrece un tipo propio, lo que permite restringir argumentos y retornos de forma clara.

Trabajar con enums evita colisiones de valores mágicos dispersos en el código y obliga al compilador a verificar que cualquier valor pertenece al dominio previsto. En proyectos empresariales este rigor reduce errores silenciosos y facilita la lectura.

Enums puros

Un enum puro declara únicamente casos sin valor subyacente. Cada caso es una instancia singleton del enum y se comporta como un objeto inmutable.

<?php

enum EstadoPedido
{
    case Pendiente;
    case Confirmado;
    case Enviado;
    case Entregado;
    case Cancelado;
}

$estado = EstadoPedido::Pendiente;

if ($estado === EstadoPedido::Pendiente) {
    echo "El pedido aun no ha sido confirmado.";
}

El tipo del enum puede usarse como type hint en firmas de métodos, lo cual aporta seguridad de tipos en cualquier lugar donde antes pasabas una cadena arbitraria.

<?php

class Pedido
{
    public function __construct(
        public readonly int $id,
        public EstadoPedido $estado,
    ) {}

    public function confirmar(): void
    {
        $this->estado = EstadoPedido::Confirmado;
    }
}

Un enum puro no tiene representación externa. No puedes persistirlo directamente en base de datos ni enviarlo tal cual por HTTP, para eso necesitas un enum backed.

La función cases() devuelve un array con todas las instancias del enum, útil para renderizar desplegables o iterar sobre el dominio completo.

<?php

foreach (EstadoPedido::cases() as $estado) {
    echo $estado->name . "\n";
}

La propiedad name existe siempre y contiene el identificador textual del caso tal y como aparece en el código.

Enums respaldados: backed enums

Un backed enum asocia a cada caso un valor escalar, de tipo string o int. Este valor se usa como representación externa cuando hay que serializar el enum a JSON, almacenarlo en base de datos o recibirlo en una petición HTTP.

<?php

enum Rol: string
{
    case Admin = "ADMIN";
    case Editor = "EDITOR";
    case Lector = "LECTOR";
}

$rol = Rol::Admin;
echo $rol->value; // "ADMIN"

La sintaxis enum Rol: string declara que los valores subyacentes son cadenas. También puede usarse int para catálogos numéricos.

Los backed enums exponen dos métodos estáticos para conversión desde el valor externo. from() devuelve la instancia o lanza ValueError si no coincide, mientras que tryFrom() retorna null en caso de valor desconocido.

<?php

$rol = Rol::from("EDITOR");      // Rol::Editor
$quizas = Rol::tryFrom("EDITOR"); // Rol::Editor
$noExiste = Rol::tryFrom("FOO");  // null

Este par de métodos resulta útil al hidratar objetos desde datos externos, por ejemplo al leer una fila de MySQL o validar un campo de formulario.

Métodos en enums

Un enum puede declarar métodos igual que una clase. Esto permite encapsular lógica cercana al dominio dentro del propio tipo, evitando dispersar switch o match por múltiples servicios.

<?php

enum EstadoPedido: string
{
    case Pendiente = "PENDIENTE";
    case Confirmado = "CONFIRMADO";
    case Enviado = "ENVIADO";
    case Entregado = "ENTREGADO";
    case Cancelado = "CANCELADO";

    public function esFinal(): bool
    {
        return match ($this) {
            self::Entregado, self::Cancelado => true,
            default => false,
        };
    }

    public function descripcion(): string
    {
        return match ($this) {
            self::Pendiente => "Pendiente de confirmacion",
            self::Confirmado => "Confirmado por el cliente",
            self::Enviado => "En ruta",
            self::Entregado => "Recibido por el destinatario",
            self::Cancelado => "Cancelado",
        };
    }
}

La expresión match ($this) recorre los casos y el compilador verifica que todos estén contemplados cuando no se usa default. Si se añade un nuevo caso al enum, el análisis estático detecta los match incompletos de inmediato.

Los enums también admiten constantes y métodos estáticos, lo que los convierte en un sitio natural para factorías cortas o valores derivados del conjunto de casos.

<?php

enum Prioridad: int
{
    case Baja = 1;
    case Media = 2;
    case Alta = 3;
    case Critica = 4;

    public const DEFECTO = self::Media;

    public static function desdeTexto(string $texto): self
    {
        return match (strtolower($texto)) {
            "baja" => self::Baja,
            "media" => self::Media,
            "alta" => self::Alta,
            "critica" => self::Critica,
            default => self::DEFECTO,
        };
    }
}

Interfaces e integracion con el dominio

Los enums pueden implementar interfaces, lo cual permite tratarlos de forma uniforme junto con otras clases del dominio que cumplen el mismo contrato.

<?php

interface TieneEtiqueta
{
    public function etiqueta(): string;
}

enum NivelSuscripcion: string implements TieneEtiqueta
{
    case Free = "FREE";
    case Pro = "PRO";
    case Enterprise = "ENTERPRISE";

    public function etiqueta(): string
    {
        return match ($this) {
            self::Free => "Gratuita",
            self::Pro => "Profesional",
            self::Enterprise => "Empresas",
        };
    }
}

La siguiente representacion resume la diferencia entre los dos tipos de enum y sus elementos principales.

flowchart TD
    A[Enum PHP 8.1] --> B[Enum puro]
    A --> C[Enum backed]
    B --> D[Casos sin valor]
    B --> E[name disponible]
    C --> F[Casos con valor string o int]
    C --> G[name y value disponibles]
    C --> H[from y tryFrom]
    A --> I[Metodos y constantes]
    A --> J[Implementa interfaces]

Esta flexibilidad permite, por ejemplo, que un servicio que traduce etiquetas reciba cualquier objeto que implemente TieneEtiqueta, sin diferenciar entre entidades de dominio y enums.

Buenas practicas al disenar enums

La eleccion entre enum puro y backed depende del uso. Si el valor nunca saldra del proceso PHP, un enum puro es mas ligero. Si necesitas persistir, serializar o recibir el valor desde un cliente externo, un backed enum con cadenas legibles resulta mas robusto que uno numerico, ya que los valores se mantienen estables ante reordenaciones.

Evita mezclar enums con constantes sueltas para el mismo dominio. Si un estado tiene enum, el resto del codigo debe consumir el enum en lugar de la constante original.

Al trabajar con frameworks modernos como Symfony o Laravel, los enums se integran directamente con la serializacion, la validacion y el mapeo a columnas de base de datos, lo cual hace que moverse al enum sea una mejora inmediata para catalogos de estados, roles y preferencias fijas de negocio.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, PHP es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de PHP

Explora más contenido relacionado con PHP y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Dominar los enums de PHP 8.1 puros y backed, añadir métodos e interfaces, y aplicarlos para modelar estados, roles y categorías con seguridad de tipos.