¿QUÉ ES UNA MÁQUINA DE ESTADOS EN PHP?
Una máquina de estados en PHP o State Machine es un patrón de diseño que modela el comportamiento de un objeto o sistema que puede estar en diferentes estados y solo puede pasar de un estado a otro mediante transiciones permitidas. es decir una máquina de estados en PHP es simplemente centralizar toda la lógica de “en qué estado estoy y a qué estados puedo ir” en un solo lugar, para que tu código sea más seguro, legible y fácil de mantener. Es como un semáforo:- Estados: Rojo → Amarillo → Verde.
- Transiciones: Solo puede ir Rojo → Amarillo, Amarillo → Verde, Verde → Rojo. Nunca puede saltar directamente de Rojo a Verde.
- Estados de pedidos (Pending → Paid → Shipped → Delivered → Cancelled).
- Flujos de videojuegos (Waiting → Joining → InProgress → Finished).
- Workflows de usuarios (Draft → PendingReview → Approved → Published).
- Tickets de soporte, reservas, suscripciones, etc.
¿Cómo se implementa en PHP?
La forma más limpia y recomendada hoy es usando Enums y métodos dentro del enum. Ejemplo práctico:enum OrderStatus
{
case Pending = 'pending';
case Paid = 'paid';
case Processing = 'processing';
case Shipped = 'shipped';
case Delivered = 'delivered';
case Cancelled = 'cancelled';
//Aquí se definen las transiciones permitidas
public function canTransitionTo(self $newStatus): bool
{
return match ($this) {
self::Pending => in_array($newStatus, [self::Paid, self::Cancelled]),
self::Paid => in_array($newStatus, [self::Processing, self::Cancelled]),
self::Processing => in_array($newStatus, [self::Shipped, self::Cancelled]),
self::Shipped => $newStatus === self::Delivered,
self::Delivered => false, // ya no se puede cambiar
self::Cancelled => false,
};
}
// Bonus: método para aplicar el cambio
public function transitionTo(self $newStatus): void
{
if (!$this->canTransitionTo($newStatus)) {
throw new \InvalidArgumentException(
"Transición inválida: {$this->value} → {$newStatus->value}"
);
}
// aquí actualizarías el modelo
}
}
//USO
$order = Order::find(1);
$current = OrderStatus::from($order->status);
$current->transitionTo(OrderStatus::Paid); // ✅ funciona
// $current->transitionTo(OrderStatus::Delivered); // ❌ lanza excepción