Clases de excepción
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 66 de 91.
En PHP, las excepciones son objetos utilizados para señalar que algo salió mal durante la ejecución. La clase base para todas las excepciones es Exception, y comprender su estructura te ayuda a manejar errores de manera efectiva en tus aplicaciones de POO.
Cuando lanzas una excepción, creas una instancia de la clase Exception (o una subclase) con un mensaje que describe qué salió mal:
<?php
class BankAccount {
public function __construct(private float $balance = 0) {}
public function withdraw(float $amount): float {
if ($amount > $this->balance) {
throw new Exception("Insufficient funds");
}
$this->balance -= $amount;
return $amount;
}
}
$account = new BankAccount(100);
$account->withdraw(150);
Esto produciría un error de excepción no capturada con el mensaje "Insufficient funds".
PHP proporciona varias clases de excepción integradas para diferentes situaciones. InvalidArgumentException señala una entrada incorrecta, RuntimeException indica errores durante la ejecución, y LogicException representa errores de programación:
<?php
class Calculator {
public function divide(int $a, int $b): float {
if ($b === 0) {
throw new InvalidArgumentException("Cannot divide by zero");
}
return $a / $b;
}
}
Cada objeto de excepción contiene información útil: getMessage() devuelve el mensaje de error, getCode() devuelve un código de error opcional, getFile() y getLine() indican dónde se lanzó la excepción. El uso de tipos de excepción específicos hace que la intención de su código sea más clara y permite un manejo de errores más preciso.
Desafío
FácilVamos a construir un sistema de gestión de inventario que utiliza las clases de excepción integradas de PHP para señalar diferentes tipos de problemas. Crearás un inventario de productos donde las operaciones pueden fallar de maneras específicas y significativas.
Organizarás tu código en tres archivos:
Product.php— Crea una claseProductque represente un artículo en el inventario. Usa la promoción de constructor para un$sku(string) público, un$name(string) público y un$quantity(int) privado. Tu clase debe tener:- Un método
getQuantity(): intque devuelva la cantidad actual - Un método
addStock(int $amount): voidque aumente la cantidad. Si la cantidad es menor que 1, lanza unaInvalidArgumentExceptioncon el mensaje"Amount must be positive" - Un método
removeStock(int $amount): voidque disminuya la cantidad. Si la cantidad es menor que 1, lanza unaInvalidArgumentExceptioncon el mensaje"Amount must be positive". Si la cantidad excede la cantidad actual, lanza unaRuntimeExceptioncon el mensaje"Insufficient stock"
- Un método
Inventory.php— Crea una claseInventoryque gestione una colección de productos. Incluye el archivo Product. Tu clase debe tener:- Un array privado para almacenar productos indexados por SKU
- Un método
addProduct(Product $product): voidque añada un producto. Si ya existe un producto con el mismo SKU, lanza unaLogicExceptioncon el mensaje"Product already exists: [sku]" - Un método
getProduct(string $sku): Productque devuelva un producto por SKU. Si no se encuentra, lanza unaInvalidArgumentExceptioncon el mensaje"Product not found: [sku]"
main.php— Incluye el archivo Inventory. Recibirás tres entradas: un SKU, un nombre de producto y una operación ("add","remove", o"duplicate").Crea un
Inventoryy añade un nuevoProductcon el SKU dado, el nombre y una cantidad inicial de10.Basado en la operación:
"add": Llama aaddStock(5)en el producto, luego imprime"Stock updated: [quantity]""remove": Llama aremoveStock(15)en el producto (esto debería lanzar una excepción)"duplicate": Intenta añadir otro producto con el mismo SKU (esto debería lanzar una excepción)
Cuando se lance una excepción, imprime el nombre de la clase de la excepción seguido de
": "y el mensaje de la excepción. Usa la funciónget_class()de PHP para obtener el nombre de la clase.
Este desafío demuestra cómo diferentes tipos de excepciones comunican diferentes tipos de problemas — entradas inválidas, fallos en tiempo de ejecución y errores de lógica — haciendo que el manejo de errores de tu código sea más preciso y significativo.
Hoja de referencia
En PHP, las excepciones son objetos que señalan errores durante la ejecución. La clase base es Exception.
Para lanzar una excepción, cree una instancia con un mensaje descriptivo:
<?php
class BankAccount {
public function __construct(private float $balance = 0) {}
public function withdraw(float $amount): float {
if ($amount > $this->balance) {
throw new Exception("Insufficient funds");
}
$this->balance -= $amount;
return $amount;
}
}
PHP proporciona clases de excepción integradas para diferentes situaciones:
InvalidArgumentException— señala una entrada no válidaRuntimeException— indica errores durante la ejecuciónLogicException— representa errores de programación
<?php
class Calculator {
public function divide(int $a, int $b): float {
if ($b === 0) {
throw new InvalidArgumentException("Cannot divide by zero");
}
return $a / $b;
}
}
Los objetos de excepción proporcionan métodos útiles:
getMessage()— devuelve el mensaje de errorgetCode()— devuelve un código de error opcionalgetFile()— devuelve el archivo donde se lanzó la excepcióngetLine()— devuelve el número de línea donde se lanzó la excepción
Use get_class() para recuperar el nombre de la clase de un objeto de excepción.
Pruébalo tú mismo
<?php
require_once 'Inventory.php';
// Leer entradas
$sku = trim(fgets(STDIN));
$name = trim(fgets(STDIN));
$operation = trim(fgets(STDIN));
try {
// TODO: Crear un Inventario
// TODO: Crear un Producto con el SKU, nombre y cantidad inicial de 10 dados
// TODO: Agregar el producto al inventario
// TODO: Basado en la operación:
// - "add": Llamar a addStock(5) en el producto, luego imprimir "Stock updated: [quantity]"
// - "remove": Llamar a removeStock(15) en el producto
// - "duplicate": Intentar agregar otro producto con el mismo SKU
} catch (Exception $e) {
// TODO: Imprimir el nombre de la clase de la excepción seguido de ": " y el mensaje
// Sugerencia: Usar get_class($e) para obtener el nombre de la clase
}
?>Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a OOPClases vs ObjetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Resumen - Calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasResumen - Jerarquía de empleados7Encapsulamiento
Público, Protegido, PrivadoModificadores de acceso a fondoGetters y SettersOcultamiento de informaciónPromoción de constructor (8.0)Resumen - Sistema de registros de estudiantes10Conceptos avanzados de POO
Composición vs. HerenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibers (PHP 8.1)Clonación de objetos a fondoGeneradores e Iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Espacios de nombres y Autoloading
Introducción a los espacios de nombresLa palabra clave useEstándar de Autoloading PSR-4Autoloader de ComposerResumen - Proyecto organizado5Interfaces y Contratos
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesInterfaz vs Clase AbstractaType Hinting con InterfacesResumen - Calculadora de Formas8Métodos mágicos
Introducción a los métodos mágicos__toString y __debugInfo__get, __set, __isset, __unset__call y __callStatic__clone y clonación de objetos__serialize y __unserializeResumen - Colección personalizada11Sistema de tipos y manejo de errores
Declaraciones de tiposTipos anulablesTipos de unión e intersecciónClases de excepciónJerarquía de excepciones personalizadasTry, Catch, FinallyResumen - Validador de formularios3Propiedades de clase
Propiedades de instancia vs. estáticasConstantes en clasesMétodos y propiedades estáticosPropiedades privadas y protegidasPropiedades de solo lectura (PHP 8.1)Resumen - Gestor de cuenta bancaria6Polimorfismo
Sobrescritura de métodos revisadaPolimorfismo mediante interfacesType Hinting y tipos de uniónEnlace estático tardíoResumen - Procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos de TraitsMétodos abstractos en TraitsTraits frente a herencia12Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy