Tema 13 · Excepciones en POO

Manejo de Excepciones Orientado a Objetos: Jerarquías y Clases Custom

Aprende a capturar y lanzar errores como objetos fuertemente tipados, crear excepciones de dominio personalizadas y estructurar bloques try-catch-finally.

¿Por qué Usar Excepciones en lugar de Devolver `false`?

En código procedimental antiguo, cuando una función fallaba se solía retornar false o -1.

Esto generaba un problema de ambigüedad: si retirarDinero() devuelve false, ¿por qué falló? ¿El saldo era insuficiente? ¿La cuenta estaba congelada por fraude? ¿El cajero se quedó sin billetes?

En la POO, los errores son Objetos. Las excepciones son objetos de primera clase que encapsulan el motivo exacto del fallo, el código de error, el archivo y la traza de pila (Stack Trace), interrumpiendo el flujo de forma segura hasta que alguien las capture.

La Jerarquía de Errores en PHP

Todas las excepciones y errores en PHP implementan la interfaz raíz Throwable:

  • Error: Errores internos graves del motor de PHP (como errores de tipado estricto TypeError o divisiones por cero DivisionByZeroError).
  • Exception: La clase base recomendada para errores de lógica de negocio y aplicaciones web.

Creación de Excepciones de Dominio Propias

Para que el código hable el lenguaje de tu negocio, creas clases que hereden de Exception o DomainException:

class SaldoInsuficienteException extends Exception {}
class TarjetaExpiradaException extends Exception {}

Esto permite capturar cada error de forma específica mediante bloques catch diferenciados.

⚡ Cajero Automático con Excepciones de Dominio Específicas

Ejecuta el código en el Sandbox y observa cómo try-catch captura errores sin tumbar la aplicación:

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

// 1. Excepciones Personalizadas de Dominio
class SaldoInsuficienteException extends Exception
{
    public function __construct(
        public readonly float $saldoActual,
        public readonly float $montoSolicitado
    ) {
        $faltante = $montoSolicitado - $saldoActual;
        parent::__construct("Fondos insuficientes: Tienes $" . number_format($saldoActual, 2) . " y solicitaste $" . number_format($montoSolicitado, 2) . ". Te faltan $" . number_format($faltante, 2));
    }
}

class CuentaBloqueadaException extends Exception {}

// 2. Clase de Negocio
class CuentaCajero
{
    public function __construct(
        private string $cliente,
        private float $saldo,
        private bool $bloqueada = false
    ) {}

    public function retirar(float $monto): void
    {
        if ($this->bloqueada) {
            throw new CuentaBloqueadaException("La cuenta de {$this->cliente} está temporalmente bloqueada por seguridad.");
        }

        if ($monto > $this->saldo) {
            throw new SaldoInsuficienteException($this->saldo, $monto);
        }

        $this->saldo -= $monto;
        echo "<p style='color:#10b981;'> Retiro exitoso de $" . number_format($monto, 2) . ". Saldo restante: $" . number_format($this->saldo, 2) . "</p>";
    }
}

// 3. Manejo con Bloque try - catch - finally
echo "<h2>Procesando Operaciones en Cajero Automático:</h2>";

$cuentas = [
    new CuentaCajero("Carlos Mendoza", 500.00, false), // Operación normal
    new CuentaCajero("Valeria Torres", 100.00, false), // Saldo insuficiente
    new CuentaCajero("Marcos Díaz",    1000.00, true), // Cuenta bloqueada
];

foreach ($cuentas as $i => $cuenta) {
    echo "<div style='font-family:system-ui; background:#f8fafc; border:1px solid #cbd5e1; border-radius:8px; padding:12px; margin-bottom:12px;'>";
    echo "<strong>Transacción #" . ($i + 1) . ":</strong>";

    try {
        // Intentar retirar $300
        $cuenta->retirar(300.00);

    } catch (SaldoInsuficienteException $e) {
        echo "<p style='color:#d97706; margin:4px 0;'>⚠️ <strong>Alerta Financiera:</strong> {$e->getMessage()}</p>";

    } catch (CuentaBloqueadaException $e) {
        echo "<p style='color:#dc2626; margin:4px 0;'>⛔ <strong>Seguridad:</strong> {$e->getMessage()}</p>";

    } catch (Throwable $e) {
        echo "<p style='color:#b91c1c;'>❌ Error general imprevisto: {$e->getMessage()}</p>";

    } finally {
        // Se ejecuta SIEMPRE, haya ocurrido error o no
        echo "<small style='color:#64748b;'>[Auditoría] Registro de auditoría guardado en el log del sistema.</small>";
    }

    echo "</div>";
}
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 la interfaz raíz que implementan todas las excepciones y errores en PHP moderno para poder ser capturados en un bloque catch?
🦉
¿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.