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.
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:
<?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();
Mini-Quiz de Retención
Comprueba tu comprensión antes de pasar a la siguiente lección¿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.