Hierarquia de Exceções Personalizada
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy. Lição 67 de 91.
Embora as classes de exceção integradas do PHP cubram cenários comuns, aplicações reais geralmente precisam de tipos de erro mais específicos. Criar uma hierarquia de exceções personalizadas permite definir exceções que correspondam ao seu domínio e capturá-las em diferentes níveis de especificidade.
Para criar uma exceção personalizada, basta estender a classe Exception ou uma de suas subclasses:
<?php
class PaymentException extends Exception {}
class InsufficientFundsException extends PaymentException {
public function __construct(
private float $required,
private float $available
) {
parent::__construct("Need $required but only $available available");
}
public function getShortfall(): float {
return $this->required - $this->available;
}
}
Observe como InsufficientFundsException estende PaymentException, e não Exception diretamente. Isso cria uma hierarquia na qual você pode capturar todas as exceções relacionadas a pagamentos com um único bloco catch ou tratar exceções específicas individualmente.
Exceções personalizadas podem incluir propriedades e métodos adicionais relevantes para o erro. Aqui, getShortfall() fornece informações úteis que uma exceção genérica não poderia oferecer:
<?php
class Wallet {
public function __construct(private float $balance) {}
public function pay(float $amount): void {
if ($amount > $this->balance) {
throw new InsufficientFundsException($amount, $this->balance);
}
$this->balance -= $amount;
}
}
Uma hierarquia de exceções bem projetada torna seu código mais fácil de manter. Ao capturar exceções, você pode ser tão abrangente ou específico quanto necessário, e os próprios objetos de exceção carregam um contexto significativo sobre o que deu errado.
Desafio
FácilVamos criar um sistema de processamento de pedidos com uma hierarquia personalizada de exceções que trata diferentes tipos de falhas de pedidos. Você criará exceções que carregam um contexto significativo sobre o que deu errado, tornando o tratamento de erros mais preciso e informativo.
Você organizará seu código em quatro arquivos:
OrderException.php: Crie uma classe baseOrderExceptionque estendaException. Ela servirá como classe pai para todas as exceções relacionadas a pedidos, permitindo capturar qualquer problema de pedido com um único bloco catch quando necessário.OutOfStockException.php: Crie uma classeOutOfStockExceptionque estendaOrderException. Essa exceção deve aceitar um nome de produto e a quantidade solicitada em seu construtor. Use a promoção de construtor para essas propriedades privadas. Chame o construtor da classe pai com uma mensagem no formato"[productName] is out of stock (requested: [quantity])". Adicione um métodogetProductName(): stringque retorne o nome do produto.InvalidQuantityException.php: Crie uma classeInvalidQuantityExceptionque estendaOrderException. Essa exceção deve aceitar um valor de quantidade em seu construtor, usando a promoção de construtor como uma propriedade privada. Chame o construtor da classe pai com a mensagem"Invalid quantity: [quantity]". Adicione um métodogetQuantity(): intque retorne o valor da quantidade.main.php: Inclua os três arquivos de exceção. Você receberá duas entradas: um nome de produto e uma quantidade (como uma string que precisa ser convertida em um inteiro).Com base no valor da quantidade, lance a exceção apropriada:
- Se a quantidade for menor que 1, lance uma
InvalidQuantityException - Se a quantidade for maior que 100, lance uma
OutOfStockException(simulando estoque insuficiente) - Caso contrário, imprima
"Order placed: [quantity]x [productName]"
Capture as exceções usando a hierarquia. Primeiro, capture
InvalidQuantityExceptione imprima"Quantity error: [message] (value: [quantity])"usando a mensagem da exceção e o métodogetQuantity(). Em seguida, captureOutOfStockExceptione imprima"Stock error: [message] (product: [productName])"usando a mensagem da exceção e o métodogetProductName().- Se a quantidade for menor que 1, lance uma
Essa hierarquia permite tratar exceções específicas individualmente e, ao mesmo tempo, manter a opção de capturar todos os problemas relacionados a pedidos por meio da classe base OrderException. Os métodos personalizados de cada exceção fornecem um contexto que uma exceção genérica não poderia oferecer.
Experimente você mesmo
<?php
// Inclua todos os arquivos de exceção
require_once 'OrderException.php';
require_once 'OutOfStockException.php';
require_once 'InvalidQuantityException.php';
// Leia a entrada
$productName = trim(fgets(STDIN));
$quantity = intval(trim(fgets(STDIN)));
// TODO: Use try-catch para lidar com o processamento do pedido
// Dentro do bloco try:
// - Se quantity < 1, throw InvalidQuantityException
// - Se quantity > 100, throw OutOfStockException
// - Caso contrário, print "Order placed: [quantity]x [productName]"
//
// Catch InvalidQuantityException primeiro:
// - Print "Quantity error: [message] (value: [quantity])" usando getMessage() e getQuantity()
//
// Catch OutOfStockException:
// - Print "Stock error: [message] (product: [productName])" usando getMessage() e getProductName()
?>Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos externosIntrodução à OOPClasses vs. objetosA palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodosA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em ProfundidadeGetters e SettersOcultação de InformaçõesPromoção de Construtor (8.0)Recapitulação - Sistema de Registros de Alunos10Conceitos Avançados de OOP
Composição vs. HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibras (PHP 8.1)Análise Profunda da Clonagem de ObjetosGeradores e Iteradores13Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository2Namespaces e Autoloading
Introdução a NamespacesA palavra-chave usePadrão de Autoloading PSR-4Autoloader do ComposerRecapitulação - Projeto organizado5Interfaces e Contratos
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataTipagem com InterfacesRecapitulação - Calculadora de Formas8Métodos Mágicos
Introdução aos Métodos Mágicos__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e Clonagem de Objetos__serialize e __unserializeRecapitulação - Coleção Personalizada11Sistema de Tipos e Tratamento de Erros
Declarações de TiposTipos NulosTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadaTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses de Livros e Usuários3Propriedades de Classes
Propriedades de Instância vs. EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Somente para Leitura (PHP 8.1)Recapitulação - Gerenciador de Contas Bancárias6Polimorfismo
Revisão da Sobrescrita de MétodosPolimorfismo via InterfacesIndicação de Tipos e Tipos UnionVinculação Estática TardiaRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos entre TraitsMétodos Abstratos em TraitsTraits vs. Herança12Padrões de Projeto – Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão StrategyPratique por conta própria: Compilador de PHP online