Clases de excepciones
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 que se utilizan para indicar que algo salió mal durante la ejecución. La clase base para todas las excepciones es Exception, y comprender su estructura te ayuda a gestionar los errores de forma eficaz en tus aplicaciones de OOP.
Cuando lanzas una excepción, creas una instancia de la clase Exception (o una subclase) con un mensaje que describe lo que 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 indica una entrada incorrecta, RuntimeException señala 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, y getFile() y getLine() te indican dónde se lanzó la excepción. Usar tipos de excepción específicos hace que la intención de tu código sea más clara y permite un manejo de errores más preciso.
Desafío
FácilConstruyamos un sistema de gestión de inventario que use las clases de excepciones integradas de PHP para indicar distintos tipos de problemas. Crearás un inventario de productos en el que 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 del 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 reduzca la cantidad. Si la cantidad es menor que 1, lanza unaInvalidArgumentExceptioncon el mensaje"Amount must be positive". Si la cantidad supera 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 los 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 y el nombre indicados, y una cantidad inicial de10.Según la operación:
"add": Llama aaddStock(5)en el producto y después 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 del 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 distintos tipos de excepciones comunican diferentes tipos de problemas —entrada no válida, fallos en tiempo de ejecución y errores lógicos—, lo que hace que el manejo de errores de tu código sea más preciso y significativo.
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: Crea un Inventory
// TODO: Crea un Product con el SKU, name y cantidad inicial de 10 dados
// TODO: Añade el producto al inventario
// TODO: Basado en la operation:
// - "add": Call addStock(5) on the product, then print "Stock updated: [quantity]"
// - "remove": Llama a removeStock(15) en el producto
// - "duplicate": Intenta añadir otro producto con el mismo SKU
} catch (Exception $e) {
// TODO: Imprime el nombre de la clase de la excepción seguido de ": " y el mensaje
// Hint: Usa 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 la POO
Archivos externosIntroducción a la POOClases frente a objetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Repaso: calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasRepaso - Jerarquía de empleados7Encapsulación
Público, protegido, privadoModificadores de acceso en profundidadGetters y settersOcultación de la informaciónPromoción del constructor (8.0)Repaso: sistema de registros de estudiantes10Conceptos avanzados de OOP
Composición vs. herenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibras (PHP 8.1)Análisis profundo de la clonación de objetosGeneradores e iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Namespaces y carga automática
Introducción a los NamespacesLa palabra clave useEstándar de carga automática PSR-4Autoloader de ComposerRepaso: proyecto organizado5Interfaces y contratos
Introducción a las interfacesImplementación de interfacesImplementación de múltiples interfacesInterfaces vs. clase abstractaTipado con interfacesRepaso - 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 __unserializeRepaso: colección personalizada11Sistema de tipos y manejo de errores
Declaraciones de tiposTipos anulablesTipos unión e intersecciónClases de excepcionesJerarquía de excepciones personalizadaTry, Catch, FinallyRepaso: 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)Repaso: gestor de cuentas bancarias6Polimorfismo
Repaso de la sobrescritura de métodosPolimorfismo mediante interfacesAnotaciones de tipo y tipos uniónEnlace estático tardíoRepaso: procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos entre TraitsMétodos abstractos en TraitsTraits frente a la herencia12Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón StrategyPractica por tu cuenta: Compilador de PHP online