Introdução: Por que o tratamento básico de erros é apenas o começo
Todo desenvolvedor PHP conhece a construção try/catch. Mas quando o projeto cresce para milhares de linhas de código e a carga no servidor se torna alta, a simples captura de exceções não é suficiente. O tratamento avançado de erros não é apenas "pegou e esqueceu", mas sim um sistema completo: desde o registro de logs até a transformação de avisos em exceções.
Neste artigo, abordaremos técnicas que o ajudarão a escrever código robusto e tolerante a falhas: múltiplos catch, classes de exceção personalizadas, manipuladores globais e integração com loggers PSR-3. O material é voltado para desenvolvedores que já conhecem os fundamentos do PHP.
1. Múltiplos blocos catch e hierarquia de exceções
A partir do PHP 7.1, você pode capturar diferentes tipos de exceções em um único bloco try. Isso permite reagir pontualmente a erros:
<?phpclass DatabaseException extends \\Exception {}class ValidationException extends \\Exception {}
try { // código que pode lançar diferentes exceções $user = $db->query('SELECT ...'); if (!$user) { throw new DatabaseException('Erro de consulta'); } if (empty($user['email'])) { throw new ValidationException('Email é obrigatório'); }} catch (DatabaseException $e) { // registra o erro do BD error_log('Erro BD: ' . $e->getMessage()); echo 'Erro temporário do servidor. Tente novamente mais tarde.';} catch (ValidationException $e) { // mostra uma mensagem clara ao usuário echo 'Erro: ' . htmlspecialchars($e->getMessage());} catch (\\Throwable $e) { // captura todo o resto (incluindo Error) error_log('Crítico: ' . $e->getMessage()); echo 'Erro crítico.';}?>Por que isso é importante? Cada tipo de exceção requer uma reação diferente. Erro de BD — ocultar detalhes do usuário, erro de validação — mostrar o formulário com o campo destacado, erro crítico — enviar uma notificação ao administrador.
Observe o \\Throwable — é a interface que é implementada tanto por Exception quanto por Error (erros fatais do PHP). Use-o no último bloco catch para não perder nenhum erro.
2. Classes de exceção personalizadas: expandindo os padrões
A classe padrão \\Exception fornece funcionalidades básicas. Mas em projetos reais, é conveniente criar suas próprias hierarquias de exceções — isso simplifica a depuração e o tratamento.
Exemplo de estrutura para uma aplicação web:
<?phpnamespace App\\Exceptions;
// Exceção base da aplicaçãoclass AppException extends \\RuntimeException{ protected $context = [];
public function __construct(string $message = '', int $code = 0, ?\\Throwable $previous = null, array $context = []) { parent::__construct($message, $code, $previous); $this->context = $context; }
public function getContext(): array { return $this->context; }}
// Exceção para erros HTTPclass HttpException extends AppException{ private int $statusCode;
public function __construct(int $statusCode, string $message = '', array $context = []) { $this->statusCode = $statusCode; parent::__construct($message, $statusCode, null, $context); }
public function getStatusCode(): int { return $this->statusCode; }}
// Usothrow new HttpException(404, 'Página não encontrada', ['uri' => $_SERVER['REQUEST_URI']]);?>Vantagens:
- É possível passar contexto adicional (parâmetros da requisição, ID do usuário) — isso simplifica o registro de logs.
- As exceções são agrupadas por significado:
HttpException,ValidationException,PaymentException.