PHP do Básico ao Avançado – Aula 8 – Tratamento de Erros e Exceções

Tempo de Leitura: 12 Minutos

Infelizmente, não importa quanto tomamos de cuido escrevendo nossos códigos, os erros são fatos da vida. O PHP reportará erros, advertências e avisos para muitos problemas comuns de codificação e problemas em tempo de execução, e saber como detectar e manusear estes erros farão o processo de depuração muito mais simples. Os erros e exceções são as respostas a inúmeras condições internas e são utilizados para sinalizar inúmeras condições diferentes, em níveis diferentes, que vão desde uma simples notificação de algo que pode ocorrer no futuro, até uma falha que impossibilita o serviço ou servidor de executar a solicitação.

Manuseio dos erros

O nível de detalhamento que o PHP usará para notificar (seja imprimento na saída padrão ou em um arquivo de log) é definido em uma diretiva do arquivo PHP.INI ou outro que esteja definido pelo servidor, na instrução error_reporting e que pode ser também alterado em tempo de execução pelo construtor  error_reporting() sendo que este manipulador seja sempre definido, em qualquer um dos níveis que permite sua alteração.

Este nível de erro, pode ser definido através de algumas constantes, no PHP 7, esses níveis são:
E_ERROR – Erros fatais em tempo de execução. Estes indicam erros que não podem ser recuperados, como problemas de alocação de memória. A execução do script é interrompida quando um erro desse tipo é disparado.
E_WARNING – Avisos em tempo de execução (erros não fatais). A execução do script não é interrompida.
E_PARSE – Erro em tempo de compilação. Erros gerados pelo interpretador. Esses erros geralmente ocorrem por erro de uma definição ou esquecimento de fechamento de um parenteses, chaves ou mesmo de um ; para término de uma instrução. A execução do script pode ser prejudicada e abortada.
E_NOTICE – Notícia em tempo de execução. Indica que o script encontrou alguma coisa que pode indicar um erro, mas que também possa acontecer a execução normal do script. Geralmente algum parâmetro de formato incorreto, ou uma constante/variável ausente. Pode causar uma falha futura, ou não.
E_CORE_ERROR – Erro fatal que acontece durante a inicialização do PHP. Este é parecido com E_ERROR, exceto que é gerado pelo núcleo do PHP. Geralmente uma biblioteca em versão errada ou desencontro de alguma configuração do php.ini e muitas vezes podem retornar como um erro 500 do servidor web que não recebe uma resposta do núclero (core) do PHP.
E_CORE_WARNING – Avisos (erros não fatais) que aconteçam durante a inicialização do PHP. Este é parecido com E_WARNING, exceto que é gerado pelo núcleo do PHP. Novamente erros não fatais causador por valores inválidos em diretivas do php.ini ou compilação.
E_COMPILE_ERROR – Erro fatal em tempo de compilação. Este é parecido com E_ERROR, exceto que é gerado pelo Zend Scripting Engine.
E_COMPILE_WARNING – Aviso em tempo de compilação. Este é parecido com E_WARNING, exceto que é geredo pelo Zend Scripting Engine.
E_USER_ERROR – Erro gerado pelo usuário. Este é parecido com E_ERROR, exceto que é gerado pelo código PHP usando a função trigger_error().
E_USER_WARNING – Aviso gerado pelo usuário. Este é parecido com E_WARNING, exceto que é gerado pelo código PHP usando a função trigger_error().
E_USER_NOTICE – Notícia gerada pelo usuário. Este é parecido com E_NOTICE, exceto que é gerado pelo código PHP usando a função trigger_error().
E_ALL – Todos erros e avisos, como suportado, exceto de nível E_STRICT este é o padrão do PHP nas versões mais novas (superior a 6).
E_STRICT – Notícias em tempo de execução. Permite ao PHP sugerir mudanças ao seu código as quais irão assegurar melhor interoperabilidade e compatibilidade futura do seu código.
E_RECOVERABLE_ERROR – Erro fatal capturável. Indica que um erro provavelmente perigoso aconteceu, mas não deixou o Engine em um estado instável. Se o erro não for pego por uma manipulador definido pelo usuário (veja também set_error_handler()), a aplicação é abortada como se fosse um E_ERROR.
E_DEPRECATED – Avisos em tempo de execução. Habilite-o para receber avisos sobre código que não funcionará em futuras versões e instruções que serão retiradas nas próximas versões do PHP.
E_USER_DEPRECATED – Mensagem de aviso gerado pelo usuário. Este é como um E_DEPRECATED, exceto que é gerado em código PHP usando a função trigger_error().

Você pode definir uma combinação delas, usando funções de bitmask no php.ini ou pode criar um arquivo de include ou função que você possa definir em tempo de execução quais valores deseja, veja o trecho de código abaixo:

<?php

$errorLevel = [
    E_ERROR             => FALSE,
    E_WARNING           => TRUE,
    E_PARSE             => TRUE,
    E_NOTICE            => TRUE,
    E_CORE_ERROR        => FALSE,
    E_CORE_WARNING      => FALSE,
    E_COMPILE_ERROR     => FALSE,
    E_COMPILE_WARNING   => FALSE,
    E_USER_ERROR        => TRUE,
    E_USER_WARNING      => TRUE,
    E_USER_NOTICE       => TRUE,
    E_STRICT            => FALSE,
    E_RECOVERABLE_ERROR => TRUE,
    E_DEPRECATED        => FALSE,
    E_USER_DEPRECATED   => TRUE,
    E_ALL               => FALSE,
];

error_reporting(
    array_sum(
        array_keys($errorLevel, $search = true)
    )
);

?>

Em outras palavras, você liga ou desliga cada um dos tipos de erro.

Outras diretrizes também podem ser definidas pelo php.ini ou em tempo de execução, e cada uma delas pode ser usada para um aspecto referente a apresentação e log de erros, são elas:

display_errors – Isso determina se os erros devem ser impressos na tela como parte da saída ou se devem ser ocultados do usuário. Os possíveis valores são “stderr” envia os erros para stderr em vez de stdout, que é a saida definida padrão (browser do usuário). “true” para habilitar a saída no browser junto com a saída do script. “false” para desabilitar a saída de erros. false deve ser o valor padrão para aplicativos e sistemas em produção.

Nota: Este é um recurso para dar suporte ao seu desenvolvimento e nunca deve ser usado em sistemas de produção (por exemplo, sistemas conectados à internet). Pois em sua saída, dados sensíveis do sistema, como senhas e strings de acesso a API’s, bancos de dados e outros podem ser apresentadas, e um hacker ou usuário mais experiente pode usar esses dados de maneira indesejada, além, de expor dados confidenciais. Embora display_errors possa ser configurado em tempo de execução (com ini_set()), ele não terá efeito se o script sofrer um erro fatal, isso ocorre porque a ação em tempo de execução desejada não é executada.

display_startup_errors – Mesmo quando display_errors está ativado, erros que ocorrem durante a sequência de inicialização do PHP não são exibidos. É altamente recomendável manter display_startup_errors desativado, exceto para depuração e configuração de um servidor, esses erros geralmente ocorrem por falhas de carga de uma biblioteca (.so no unix/posix e .dll no windows) ou de algum erro presente no php.ini ou outro arquivo de configuração de inicialização.  Os valores possíveis são true ou false.

log_errors – Informa se as mensagens de erro de script devem ser registradas no log de erros do servidor ou no arquivo de error_log. Essa opção é, portanto, específica do servidor e é altamente recomendável usar o registro de erros em vez de exibir erros em sites de produção. Os valores possíveis são true e false.

log_errors_max_len – Define o tamanho máximo do arquivo error_log, em bytes. O padrão é 1024 e 0 não determina um tamanho, podendo ocupar todo o espeço em disco. Esse tamanho é aplicado a erros registrados, erros exibidos e também a $php_errormsg, mas não à funções chamadas explicitamente como error_log().

ignore_repeated_errors – Não registrar mensagens repetidas. Erros repetidos devem ocorrer no mesmo arquivo e na mesma linha, a menos que ignore_repeated_source seja definido como verdadeiro (true). Isso é util quando colocado em sistemas de produção ou homologação, pois permite que os desenvolvedores vejam os erros que ocorreram, e mesmo que algumas centenas de requisições e erros sejam disparadas, somente 1 ficará logada, economizando o espaço e até mesmo o tempo de leitura desse arquivo.

ignore_repeated_source – Ignora a fonte da mensagem quando estiver ignorando mensagens repetidas. Quando esta configuração estiver On, você não registrará erros com mensagens repetidas de arquivos ou linhas diferentes. É mais utilizada em produção, já que mostra os erros, porém nas fases de depuração pode ser mais difícil localizar a sua origem.

report_memleaks – Se este parâmetro estiver definido como On (o padrão), mostrará um relatório de vazamentos de memória detectados pelo gerenciador de memória do Zend. Este relatório será enviado para stderr em plataformas Posix. No Windows, ele será enviado ao depurador usando o OutputDebugString() e poderá ser visualizado com ferramentas como o » DbgView. Este parâmetro só tem efeito em uma compilação de depuração, e se error_reporting incluir E_WARNING na lista de permitidos.

track_errors – Se habilitado, a última mensagem de erro estará sempre presente na variável $php_errormsg, ideal para salvar ou utilizar para envio de saídas ou tratamentos personalizados.

html_errors – Se ativado, as mensagens de erro incluirão tags HTML. O formato para erros de HTML produz mensagens clicáveis que direcionam o usuário para uma página descrevendo o erro ou a função que está causando o erro. Se desativado, a mensagem de erro será apenas texto simples. OFF é o valor padrão.

xmlrpc_errors – Se ativado, desativa o relatório de erros normal e formata os erros como mensagem de erro XML-RPC. Útil se você estiver desenvolvendo aplicações de back-end com saídas em XML.

xmlrpc_error_number – Usado como o valor do elemento faultCode do XML-RPC.

docref_root – O novo formato de erro contém uma referência a uma página que descreve o erro ou a função que está causando o erro. No caso de páginas de manual, você pode baixar o manual em seu idioma e definir esta diretiva ini para a URL da sua cópia local. Este é um recurso para dar suporte ao seu desenvolvimento, ou a equipe de desenvolvedores, pois facilita a pesquisa da descrição de uma função, ou abre o espaço para que você crie páginas de manual para outros desenvolvedores usarem por exemplo o seu framework etc. No entanto, nunca deve ser usado em sistemas de produção.

error_prepend_string – String para mostrar antes de uma mensagem de erro. É útil caso você queira apresentar para o usuário a mensagem de erro fornecida pelo php, por exemplo em uma console do navegador, ou dentro de uma caixa ou tag específicas.

error_append_string – String para mostrar após uma mensagem de erro. O uso prático dessas duas diretrizes é por exemplo colocar a mensagem de erro por exemplo em uma fonte vermelha, usamos como prepend <font color=red> e como append </font>

error_log – Nome do arquivo onde os erros de script devem ser registrados. O arquivo deve ter permissão de escrita pelo usuário do servidor da web. Se o valor especial syslog for usado, os erros serão enviados ao registrador de erros do sistema. No Unix, isso significa syslog(3) e no Windows significa o log de eventos. Veja também: syslog(). Se esta diretiva não estiver definida, os erros serão enviados para o registrador de erros SAPI. Por exemplo, é um log de erros no Apache ou stderr no CLI. Veja também error_log(). Note que o windows e o unix usam formatos diferentes para a colocação de diretórios.

syslog.facility – Especifica qual tipo de programa está registrando a mensagem. Somente é efetivo se error_log estiver definido como “syslog”.

syslog.filter – Especifica o tipo de filtro para filtrar as mensagens registradas. Caracteres permitidos são passados sem modificações; todos os outros são escritos em sua representação hexadecimal prefixado com \x. Existem três tipos de filtros suportados:  all – todos os caracteres no-ctrl – todos os caracteres, exceto os caracteres de controle e ascii – todos os caracteres ASCII imprimíveis e NL. Somente é efetivo se error_log estiver definido como “syslog”.

syslog.ident – Especifica a string ident que é anexada a todas as mensagens. Somente é efetivo se error_log estiver definido como “syslog”.

Uma boa prática

Em um ambiente de desenvolvimento, deve-se sempre definir a diretiva error_reporting para E_ALL, para estar ciente, e corrigir, problemas informados pelo PHP. Em produção, deve-se definir para um nível menos verboso, como E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED, mas em muitos casos E_ALL também é apropriado, pois pode antecipar avisos de problemas em potencial.

O PHP manipula estes erros conforme outras duas diretivas no php.ini. A diretiva display_errors controla se o erro será mostrado como parte da saída do script. Esta diretiva deve sempre estar desativada no ambiente de produção, já que pode incluir informações confidenciais como senhas do banco de dados, mas é útil habilitá-la em desenvolvimento, já que garante o reporte imediato de problemas. Além de mostrar os erros, o PHP pode logar erros quando a diretiva log_errors estiver habilitada. Isso logará qualquer erro para um arquivo ou para o syslog definido com a diretiva error_log. Pode ser extremamente útil no ambiente de produção, já que pode-se logar os erros que ocorrerem e então gerar relatórios baseados nestes erros.

Mais a frente, veremos o uso de funções específicas para o tratamento de error, como a set_error_handler() onde podemos criar nosso próprio manipulador de erros.

error_reporting()

Podemos capturar o nível atual de erro, para uma variável por exemplo no código

<?php
    $erroStatus = error_reporting(0); //capturamos o valor existente, e desligamos os erros
    /* neste ponto, definimos o código onde não queremos que os erros sejam apresentados, ou onde queremos um errorlevel diferente */
    error_reporting ($erroStatus) ; // setamos novamente o nível para o que existia antes
?>

Um código útil, por exemplo se estamos recebendo valores opcionais ou recebendo dados da manipulação de respostas ou processamentos feitos em outro servidor, ou em algum micro serviço que pode estar indisponível no momento da requisição.

NO PHP 7 e versões mais novas

O PHP 7 modificou como a maioria dos erros são reportados, em vez de reportá-los através do mecanismo tradicional, a maioria dos erros, agora são reportados lançando exceções Error. Assim como exceções normais, as exceções Error serão elevadas até alcançarem o primeiro bloco catch correspondente. Se não existir nenhum bloco correspondente, qualquer manipulador de exceção padrão instalado com a função set_exception_handler() será chamado, e se não existir nenhum manipulador padrão de exceção, a exceção será convertida em um erro fatal e tratada como um erro tradicional.

Já que a hierarquia de Error não herda de Exception, códigos que utilizam blocos catch (Exception $e) { … } para manipular exceções que não foram capturadas no PHP 5, descobrirão que estes Errors não são capturados por estes blocos, veja um exemplo:

try
{
   // Codigo que possa gerar um erro ou uma excessão
}
catch (Throwable $t)
{
   // Executado somente se tiver o PHP7
}
catch (Exception $e)
{
   // Executado somente no PHP5, este bloco pode ser removido se a versão for maior ou igual a 7
}

Trabalhando com exceções

<?php
function inverse($x) {
    if (!$x) {
        throw new Exception('Divisão por zero.');
    }
    return 1/$x;
}

try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'Exceção capturada: ',  $e->getMessage(), "\n";
}

// Execução continua
echo "Olá mundo\n";
?>

O exemplo acima vai resultar na seguinte saída:

0.2
Exceção capturada: Divisão por zero.
Olá mundo

Este formato é a maneira correta de devolver mensagens de erro usando a orientação a objetos, e o throw obrigatoriamente deve ser uma instância da classe Exception, caso contrário será gerado um erro fatal. Múltiplos blocos catch podem ser utilizados para capturar exceções diferentes. Quando uma exceção é lançada o código seguinte não é executado, e o PHP tentará encontrar o primeiro bloco catch coincidente. A partir do PHP 7.1 um bloco catch pode especificar múltiplas exceções usando o caractere pipe (|). Isto é útil quando diferentes exceções de diferentes hierarquias de classes são tratadas da mesma forma.

Conclusão

Até este ponto, você já conheceu praticamente todos os recursos da linguagem PHP, na próxima aula, vamos finalizar esse módulo, onde falamos sobre as estruturas da linguagem tratando dos útimos tipos de dados e outros construtores presentes na linguagem. Neste momento, você já conhece todas as estrutura necessárias para programar utilizando o PHP, e integra-lo ao desenvolvimento de seus sites e sistemas baseados em web.