Tratamento global de erros
Esta aula ensina como configurar tratadores globais de erros e exceções em PHP, usando set_error_handler e set_exception_handler, além de práticas de logging e diferenças entre ambientes de produção e desenvolvimento.
No desenvolvimento de aplicações PHP robustas, o tratamento de erros não pode ser deixado ao acaso. Em vez de depender apenas dos mecanismos padrão do PHP, que muitas vezes exibem mensagens técnicas inadequadas para o usuário final, podemos assumir o controle total sobre como erros e exceções são gerenciados. Esta aula ensina como configurar funções globais de tratamento de erros e exceções, implementar logging eficiente e adaptar o comportamento do sistema entre ambientes de desenvolvimento e produção.
Dominar essas técnicas é essencial para criar aplicações resilientes, que se comportam de forma previsível mesmo diante de falhas inesperadas, além de facilitar a depuração e a manutenção do código.
set_error_handler
A função set_error_handler permite definir uma função personalizada que será chamada sempre que um erro não fatal ocorrer no PHP (como warnings, notices ou erros de usuário). Isso substitui o manipulador de erros padrão, dando a você controle total sobre como esses eventos são tratados.
A função de callback recebe parâmetros como o nível do erro, a mensagem, o arquivo e a linha. Você pode decidir se quer exibir, logar ou ignorar o erro. É importante lembrar que erros fatais (E_ERROR, E_PARSE, etc.) não podem ser capturados por esse mecanismo, pois eles interrompem a execução do script imediatamente.
function meu_manipulador_erro($nivel, $mensagem, $arquivo, $linha) {
// Loga o erro em um arquivo
error_log("Erro [$nivel]: $mensagem em $arquivo:$linha", 3, '/var/log/meu_app.log');
// Exibe uma mensagem amigável para o usuário final
echo "Ocorreu um erro interno. Por favor, tente novamente mais tarde.";
// Impede que o PHP execute o manipulador padrão
return true;
}
set_error_handler('meu_manipulador_erro');
// Gera um warning (exemplo)
echo 10 / 0;set_exception_handler
Enquanto set_error_handler lida com erros tradicionais, set_exception_handler captura exceções não tratadas que chegam ao topo da pilha de chamadas. Isso é útil para garantir que nenhuma exceção escape sem ser registrada ou exibida de forma adequada.
A função de callback recebe um objeto Exception (ou Throwable) como parâmetro. Você pode logar os detalhes, enviar notificações e exibir uma página de erro personalizada. Lembre-se de que exceções capturadas por blocos try-catch não passam por esse manipulador.
function meu_manipulador_excecao($excecao) {
// Loga a exceção
error_log("Exceção: " . $excecao->getMessage() . " em " . $excecao->getFile() . ":" . $excecao->getLine());
// Exibe uma página de erro 500
http_response_code(500);
echo "Erro Interno do Servidor
Desculpe, algo deu errado.
";
}
set_exception_handler('meu_manipulador_excecao');
// Lança uma exceção não tratada
throw new Exception("Algo falhou!");Logging
Logging é a prática de registrar eventos importantes (erros, avisos, informações) em um arquivo ou sistema externo. Em PHP, a função error_log é a ferramenta básica, mas bibliotecas como Monolog oferecem recursos avançados (níveis de log, rotação de arquivos, envio por e-mail).
Um bom logging deve incluir timestamp, nível de severidade, mensagem descritiva e contexto (arquivo, linha, variáveis). Evite logar informações sensíveis (senhas, tokens) e defina rotação para evitar que arquivos cresçam indefinidamente. Em produção, logs são cruciais para depuração pós-mortem.
// Logging simples com error_log
error_log("Usuário tentou acessar recurso restrito", 0);
// Envia para um arquivo específico
error_log("Erro de banco de dados", 3, '/var/log/app_errors.log');
// Exemplo com Monolog (requer Composer)
// use Monolog\Logger;
// use Monolog\Handler\StreamHandler;
// $log = new Logger('nome');
// $log->pushHandler(new StreamHandler('/var/log/app.log', Logger::WARNING));
// $log->warning('Mensagem de aviso');Produção vs desenvolvimento
Em desenvolvimento, é útil exibir erros detalhados na tela para facilitar a depuração. Em produção, porém, você deve ocultar todos os detalhes técnicos do usuário final e logar os erros internamente. Isso protege informações sensíveis e melhora a experiência do usuário.
Configure o PHP de acordo com o ambiente: em desenvolvimento, use display_errors = On e error_reporting = E_ALL. Em produção, desative display_errors e mantenha log_errors = On. Utilize variáveis de ambiente ou arquivos de configuração separados para alternar entre modos.
// Exemplo de configuração condicional
if (getenv('APP_ENV') === 'development') {
ini_set('display_errors', 1);
ini_set('error_reporting', E_ALL);
} else {
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php_errors.log');
}
// Seu código aqui...Boas práticas e observações finais
Sempre registre o máximo de contexto possível nos logs (identificador do usuário, URL, dados da requisição). Use níveis de log (debug, info, warning, error) para filtrar mensagens. Evite usar @ para suprimir erros; prefira tratá-los adequadamente. Teste seus manipuladores em ambiente de desenvolvimento antes de implantar em produção.
Lembre-se de que set_error_handler não captura erros fatais; para isso, considere usar register_shutdown_function para capturar o último erro fatal via error_get_last. Integre ferramentas de monitoramento como Sentry ou Bugsnag para alertas em tempo real.
Referências
- PHP: set_error_handler - Manual
- PHP: set_exception_handler - Manual
- PHP: error_log - Manual
- PSR-3: Logger Interface
- Monolog - Documentação oficial
- PHP: register_shutdown_function - Manual
Exercícios
Crie um manipulador de erros personalizado que converta todos os warnings e notices em exceções do tipo
ErrorException. Em seguida, registre-o usandoset_error_handler.✓ Resposta:function error_to_exception($nivel, $mensagem, $arquivo, $linha) { throw new \ErrorException($mensagem, 0, $nivel, $arquivo, $linha); } set_error_handler('error_to_exception'); // Teste: try { echo 10 / 0; } catch (\ErrorException $e) { echo "Capturado: " . $e->getMessage(); }Implemente um manipulador de exceções global que registre a exceção em um arquivo de log e exiba uma mensagem amigável “Erro interno do servidor” com código HTTP 500.
✓ Resposta:function global_exception_handler($exception) { error_log("Exceção: " . $exception->getMessage() . " em " . $exception->getFile() . ":" . $exception->getLine()); http_response_code(500); echo "Erro interno do servidor
Desculpe, algo deu errado.
"; } set_exception_handler('global_exception_handler'); throw new \Exception("Teste");Configure o PHP para exibir erros detalhados apenas em ambiente de desenvolvimento, usando uma variável de ambiente
APP_ENV. Em produção, desative display_errors e ative log_errors.✓ Resposta:$env = getenv('APP_ENV') ?: 'production'; if ($env === 'development') { ini_set('display_errors', 1); ini_set('error_reporting', E_ALL); } else { ini_set('display_errors', 0); ini_set('log_errors', 1); ini_set('error_log', '/var/log/php_errors.log'); }Escreva um script que use
error_logpara registrar uma mensagem de nível info com o timestamp atual em um arquivoapp.log. Inclua também a URL da página atual.✓ Resposta:$url = $_SERVER['REQUEST_URI'] ?? 'desconhecida'; $mensagem = date('Y-m-d H:i:s') . " - Info: Acesso à página $url"; error_log($mensagem, 3, '/var/log/app.log');Crie um manipulador de shutdown que capture o último erro fatal (se houver) e registre-o em um arquivo de log. Use
register_shutdown_functioneerror_get_last.✓ Resposta:function shutdown_handler() { $error = error_get_last(); if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) { error_log("Erro fatal: " . $error['message'] . " em " . $error['file'] . ":" . $error['line']); } } register_shutdown_function('shutdown_handler'); // Teste: descomente a linha abaixo para gerar um erro fatal // undefined_function();