Tema 9 · Enums en PHP 8.1

Enums Nativos en PHP 8.1+: Tipado Estricto de Estados de Negocio

Aprende a sustituir cadenas mágicas y constantes dispersas por Enums nativos en PHP 8 para tipar estados de negocio con autocompletado y validación estricta.

El Fin de las "Cadenas Mágicas" (Magic Strings)

Históricamente en PHP, los estados de una entidad (como un pedido o un usuario) se gestionaban con texto libre: $pedido->estado = 'pagado';.

El problema evidente son los errores tipográficos que no se detectan hasta producción: si alguien escribe 'pagdo' o 'PAID', la base de datos se corrompe y los condicionales fallan silenciosamente.

La Novedad de PHP 8.1: Enums Nativos. Un enum es un tipo de dato exclusivo que restringe el valor de una variable a un conjunto cerrado de casos válidos conocidos en tiempo de compilación.

Enums Puros vs. Backed Enums (Respaldados)

En aplicaciones web conectadas a bases de datos MariaDB/MySQL, los más utilizados son los Backed Enums (respaldados por un valor string o int):

enum EstadoPedido: string {
    case Pendiente = 'pending';
    case Pagado    = 'paid';
    case Enviado   = 'shipped';
    case Cancelado = 'cancelled';
}
Operación con Enum Sintaxis en PHP Resultado / Utilidad
Obtener el valor escalar EstadoPedido::Pagado->value Retorna 'paid' (listo para guardar en la BD).
Obtener el identificador EstadoPedido::Pagado->name Retorna el nombre literal 'Pagado'.
Convertir desde la BD (Estricto) EstadoPedido::from('paid') Devuelve la instancia o lanza ValueError si no existe.
Convertir de forma segura EstadoPedido::tryFrom('invalido') Devuelve null en lugar de romper el script.

Métodos dentro de Enums

En PHP, los enums pueden contener métodos reales, lo que permite centralizar toda la lógica asociada a un estado (como colores de badges HTML o descripciones en español):

⚡ Gestión de Estados de Pedido con Enums Nativos y Métodos HTML

Ejecuta el código en el Sandbox y observa cómo los Enums validan estados y formatean la interfaz:

EstadoPedido.php
Solo lectura
<?php
declare(strict_types=1);

// 1. Definición del Enum Respaldado (Backed Enum)
enum EstadoPedido: string
{
    case Pendiente = 'pending';
    case Procesando = 'processing';
    case Pagado    = 'paid';
    case Cancelado = 'cancelled';

    // Método dentro del enum: Devuelve el texto legible en español
    public function getEtiqueta(): string
    {
        return match($this) {
            self::Pendiente  => '⏳ Pago Pendiente',
            self::Procesando => '🔄 En Preparación',
            self::Pagado     => ' Aprobado & Pagado',
            self::Cancelado  => '❌ Pedido Cancelado',
        };
    }

    // Método que devuelve el color del badge para la interfaz
    public function getColorBadge(): string
    {
        return match($this) {
            self::Pendiente  => '#f59e0b', // Naranja
            self::Procesando => '#0284c7', // Azul
            self::Pagado     => '#10b981', // Verde
            self::Cancelado  => '#ef4444', // Rojo
        };
    }
}

// 2. Clase de Dominio que utiliza el Enum fuertemente tipado
final class Pedido
{
    public function __construct(
        public readonly int $id,
        public readonly string $cliente,
        public readonly float $total,
        private EstadoPedido $estado = EstadoPedido::Pendiente
    ) {}

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

    public function renderTarjeta(): void
    {
        $color = $this->estado->getColorBadge();
        $texto = $this->estado->getEtiqueta();
        $valorBD = $this->estado->value;

        echo "<div style='font-family:system-ui; border:1px solid #cbd5e1; border-radius:8px; padding:15px; margin-bottom:12px; background:#fff;'>";
        echo "<div style='display:flex; justify-content:space-between; align-items:center;'>";
        echo "<h4 style='margin:0;'>Pedido #{$this->id} - {$this->cliente}</h4>";
        echo "<span style='background:{$color}; color:white; padding:4px 10px; border-radius:6px; font-size:12px; font-weight:bold;'>{$texto}</span>";
        echo "</div>";
        echo "<p style='margin:8px 0 0 0; color:#475569;'>Total: <strong>$" . number_format($this->total, 2) . "</strong> | Valor en Base de Datos: <code>{$valorBD}</code></p>";
        echo "</div>";
    }
}

// ==========================================
// PRUEBA EN EL SANDBOX
// ==========================================
$pedido1 = new Pedido(501, "Alejandra Ruiz", 185.00, EstadoPedido::Pagado);
$pedido2 = new Pedido(502, "Marcos Duarte", 420.50, EstadoPedido::Pendiente);
$pedido3 = new Pedido(503, "Camila Soto", 99.00, EstadoPedido::Cancelado);

echo "<h2>Lista de Pedidos con Tipado Estricto de Enums:</h2>";
$pedido1->renderTarjeta();
$pedido2->renderTarjeta();
$pedido3->renderTarjeta();

// Demostración de conversión desde la base de datos:
$estadoDesdeBD = EstadoPedido::from('processing'); // Devuelve EstadoPedido::Procesando
$pedido2->cambiarEstado($estadoDesdeBD);

echo "<h3>Estado de Pedido #502 Actualizado Dinámicamente:</h3>";
$pedido2->renderTarjeta();
Pruébalo tú mismo » Se abre en una nueva pestaña con ejecución en vivo
🧠
Mini-Quiz de Retención
Comprueba tu comprensión antes de pasar a la siguiente lección
1 Pregunta
Pregunta 1
¿Cuál es el método nativo que permite instanciar un Backed Enum a partir de un valor de base de datos sin lanzar una excepción si el valor no existe?
🦉
¿Tienes dudas con este tema?
Sócrates AI puede darte analogías y explicarte este código paso a paso.

🚀 ¿Quieres dominar Manual de Programación Orientada a Objetos en PHP (POO) y crear proyectos reales?

Aprende arquitectura limpia, desarrollo web moderno, buenas prácticas y despliegue en producción con nuestro Bootcamp Fullstack Developer con mentorías en vivo.

🏛️ Autoría y Propiedad Intelectual: Obra educativa original de David Amador para Kilopolis Academia (Solucionáticos), estructurada sobre las especificaciones y estándares abiertos del W3C, el estándar vivo de WHATWG y la documentación oficial de código abierto. © Todos los derechos reservados.