Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Anderson Mello

Tratamento de erros

Recommended Posts

Tratamento de Erros

  • [*]1. O que é tratamento de erros [*]2. Boas maneiras para programar sem erros [*]3. Como debugar um script [*]4. Validações para evitar erros [*]5. Tratando erros com Exceções

1. O que é tratamento de erros

Tratar um erro nada mais é do que preparar para rodar em qualquer situação ou, se não for possível, avisar por que não pôde ser executado. Tratando um erro você pode esperar uma situação e contorná-la ou, se não tiver jeito, finalizar a execução de uma forma segura e que não deixe o usuário sem saber o que está acontecendo. Ao fazer um tratamento de erros adequado, você pode preparar mensagens personalizadas para avisar os usuários que o sistema não pôde ser executado e notificar o erro ao administrador do site, para ele saber exatamente o que aconteceu e como proceder para corrigir o problema. Além disso, é útil para criação de estatísticas de erros.

2. Boas maneiras para programar sem erros

Além de fazer um tratamento de erros adequado, você precisa programar de uma maneira que evite erros. Existem vários meios de gerar erros no seu sistema e, sabendo como evitá-los, você deixar seu sistema mais profissional e à prova de falhas. Possíveis causas de erros no sistema:

  • [*]Programar de maneira errada [*]Esconder erros [*]Falta de uma lógica mais apurada e desenvolvida [*]Não pensar nos usuários [*]Falta de conhecimento na linguagem com a qual se está programando [*]Falha por parte de
hardware

Explicarei um pouco sobre cada um.

2.1 Programar de maneira errada
Esta tem suas principais causas: preguiça, pressa, falta de planejamento e/ou falta de conhecimento. A preguiça é porque na maioria das vezes o programador não quer saber como faz, mas, sim, entregar o sistema o mais rápido possível. Ele procura scripts prontos na Internet, só edita algumas coisas fáceis e acaba fazendo uma salada mista de vários sistemas prontos, tudo mal feito. O resultado é um sistema cheio de erros. Quanto mais o programador estudar e procurar entender para fazer seus sistemas, mais eles ficarão enxutos e livres de erros.

A pressa é outra vilã. O programador acaba fazendo um monte de gambiarras e pensa assim: "Ah, depois de entregar o sistema eu arrumo os erros com calma. O mais importante é entregar no prazo!", e acaba nunca arrumando. Falta de planejamento também é muito ruim e acontece quando o programador mal pegou o serviço e já quer fazer tudo de uma vez, sem pensar em como o desenvolverá. Como resultado, acaba fazendo o sistema, depois o banco de dados, e depois sai costurando as falhas até deixar tudo funcionando. Tenha calma e não se apresse em fazer. Em um sistema bem feito, 70% dele é planejamento e o restante, escrever os códigos, modelar um banco de dados de forma correta, etc.

Já a pior das causas é a falta de conhecimento, pois é comum pessoas mal saberem o que é um HTML e já querem programar em PHP. Em alguns casos, conseguem até clientes e sempre aparecem desesperadamente nos fóruns pedindo ajuda para fazer um sistema para eles. Conseqüentemente nunca farão um sistema bem feito, até aprenderem a fazê-los por conta própria. Outros programadores têm até certo conhecimento, mas não o usa, enquanto outros chegam a um limite e param, acreditando que não precisam aprender mais nada. Aí surgem com aquela frase: "Em time que está ganhando não se mexe!". Já vi programadores com 40 anos nas costas que usam o mesmo sistema que aprenderam a fazer no passado. Não querem evoluir ou aprender coisas novas, e aí acabam escondendo erros em vez de tratá-los.

Existem várias maneiras de se esconder erros no PHP e muitos têm abusado desses recursos. Não se devem esconder erros!. Claro que num site já publicado você não pode deixar que usuários vejam erros do seu sistema, mas nem por isso se deve escondê-los. Se o sistema tem falhas deixe uma mensagem avisando que logo ele estará funcionando, em vez disso, por exemplo, mostrando um erro grotesco e que não significa nada ao usuário leigo, além de expor informações internas do seu sistema, como por exemplo Warning: mysql_connect() [function.mysql-connect]: Access denied for user 'root'@'localhost' (using password: NO) in...

Muitas vezes eu falo que esconder erros é a mesma coisa que varrer a sujeira para debaixo do tapete. Não vou entrar em detalhes na parte de boas maneiras ao programar, porque já publicamos um artigo sobre isso (leia-o aqui).

2.2 Esconder Erros
Agora vou explicar como esconder um erro do PHP e como fazer para mostrar mensagens personalizadas. Os erros têm que ser escondidos em certos casos porque senão o PHP acaba mostrando mensagens de erros para o usuário, por exemplo:

Exemplo 2.2.1 Operadores de controle de erro (retirado do Manual do PHP)
O PHP suporta um operador de controle de erro: o sinal 'arroba' (@). Quando ele precede uma expressão em PHP, qualquer mensagem de erro que possa ser gerada por ela será ignorada.
Se o recurso track_errors estiver habilitado, qualquer mensagem de erro gerada pela expressão será gravada na variável global $php_errormsg. Esta variável será sobrescrita em cada erro, assim verifique-a constantemente se você quiser usá-la.

<?php/* Erro intencional de arquivo */$my_file = @file ('arquivo_nao_existente') or die("Falha abrindo arquivo: '$php_errormsg'");// Isto funciona para qualquer expressão, não apenas para funções:$valor = @$carrinho[$produto];// você não receberá nenhum aviso se a chave $produto não existir.?>


Nota: o operador @ funciona somente em expressões. Uma regra simples para lembrar disso: se você pode pegar o valor de alguma coisa, você pode prefixar isso com o @. Assim, você pode prefixar chamadas de variáveis, funções e include()'s, constantes e afins. Você não pode prefixar definições de funções ou classe, estruturas condicionais como o if, foreach e assim por diante.


Exemplo 2.2.2 Ocultar erro em conexões com banco de dados
Usando o @ você pode ocultar erros de conexões com o banco de dados:

 

<?php@mysql_connect("localhost", "root") or die("Mensagem de erro");?>


Usando o @ podemos ocultar a mensagem de erro do PHP, mas devemos, ainda, informar o usuário e exibir uma mensagem de erro personalizado, podendo usar CSS, imagens etc. O mesmo vale para erros na abertura de arquivos ou envio de e-mails.

Outra maneira de ocultar erros é editando o PHP.INI na linha "display_errors = off". Muitos programadores, por não saberem configurar corretamente o PHP.INI, deixam-no no padrão de instalação e, dependendo da versão do PHP, o display_errors está em "off". O que recomendo é deixar em "on", caso contrário, o PHP não irá mostrar os erros, caso ocorram. Eu vejo erros comuns pelos fóruns, tipo esse:

Exemplo 2.2.3 Índice não encontrado

 

 

$val = $_POST[val]; // erro não delimitou uma string com aspas ou apóstrofos


Daí eu falo para o usuário que ele precisa delimitar as strings com aspas, por exemplo, $_POST["val"]. Mas o usuário acaba comentando: "Mas assim também funciona e não tem erro!". Isso acontece porque o display_errors dele esta em "off" e por isso não consegue perceber o erro. O PHP entende, conforme o exemplo acima, que val é uma constante. Não a encontrando, assume como uma string e exibe um erro do tipo E_NOTICE.

Exemplo 2.2.4 Ocultar erros com error_reporting() (retirado do Manual do PHP)

A função error_reporting() define a diretiva error_reporting em tempo de execução. O PHP tem vários níveis de erros, usando essa função você pode definir o nível durante a execução do seu script. error_reporting() define o nível de erros que o PHP irá reportar, e retorna o nível antigo. O parâmetro nível pode usar um bitmask, ou constantes. É fortemente recomendado que você use constantes para assegurar compatibilidade com futuras versões. Como níveis de erros podem ser adicionados, o intervalo das constantes pode crescer, então os níveis de erros indicados anteriormente por inteiros podem não funcionar como esperado.

Exemplo 1. Exemplos error_reporting()

 

 

<?php// Desativa o relatório de todos os erroserror_reporting(0);// Reporta erros simpleserror_reporting(E_ERROR | E_WARNING | E_PARSE);// Reportar E_NOTICE pode ser bom também (para reportar variáveis não iniciadas// ou erros de digitação em nomes de variáveis ...)error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);// Reportar todos os erros exceto E_NOTICE// Este é o valor padrão no php.inierror_reporting(E_ALL ^ E_NOTICE);// Reporta todos os erros (bitwise 63 deve ser usado no PHP 3)error_reporting(E_ALL);// O mesmo que error_reporting(E_ALL);ini_set('error_reporting', E_ALL);?>


Os níveis de erros disponíveis estão listados abaixo. A descrição deles está em constantes predefinidas.

 

  • [*]1 E_ERROR [*]2 E_WARNING [*]4 E_PARSE [*]8 E_NOTICE [*]16 E_CORE_ERROR [*]32 E_CORE_WARNING [*]64 E_COMPILE_ERROR [*]128 E_COMPILE_WARNING [*]256 E_USER_ERROR [*]512 E_USER_WARNING [*]1024 E_USER_NOTICE [*]2047 E_ALL [*]2048 E_STRICT

Atenção
A partir do PHP 5.0.0, E_STRICT com o valor 2048 está disponível. E_ALL NÃO mostra erros do nível E_STRICT.

Recomendo deixar error_reporting(E_ALL), para mostrar todos os tipos de erros.


2.3 Falta de uma lógica mais apurada e desenvolvida
Agora falando sobre lógica! Muitos erros acontecem também por falta de uma lógica correta, ou seja, programam de maneira errada, fazem gambiarra (famosa POG - Programação Orientada à Gambiarras)) ou complicam demais algo que poderia ser mais simples. Já vi muitos usuários não saberem manipular datas, como somar, subtrair, etc. Acabam fazendo cada loucura com uma coisa simples. Falta de lógica pode fazer com que o sistema fique com erros e, por azar, o programador não percebe até que o erro aconteça.

2.4 Não pensar nos usuários
Não pensar nos usuários também pode fazer com que o sistema tenha erros. Um exemplo disso é o programador ter um micro de último tipo, e configurar o PHP.INI a seu gosto, com programas atualizados e acaba desenvolvendo pensando só nele. Esquece que outros usuários que irão usar o sistema não têm o mesmo recurso. Por exemplo: o programador faz um sistema usando PHP 5.2, Apache 2.2.4, Mysql 5 e disponibiliza o sistema para outros usuários e o coitado do usuário baixa o sistema e vai rodar num servidor com PHP 4 e Mysql 3 (a grande maioria dos servidores de hospedagem demoram para se atualizarem). Aí o sistema não funciona e aparecerá um monte de mensagens de erros e o usuário nem sabe o porquê. Não estou falando que não se deve programar usando as últimas versões, mas tem que ver pra qual situação será usado o sistema e verificar se o sistema está apto a rodar na plataforma em que foi instalado.

2.5 Falta de conhecimento da linguagem com a qual se está programando
Falta de conhecimento na linguagem PHP também faz o sistema ter muitos erros. Muitas vezes o usuário é até esforçado, mas por falta de conhecimento não sabe identificar um erro ou um problema e muito menos fazer de um jeito melhor. Acaba pegando scripts prontos para aprender, mas estes também estão sujeitos a erros e o usuário vai querer editar, deixando-o cada vez pior. Por falta de conhecimento na linguagem também acontecem muitos erros de concatenação de strings, tags PHP, ou juntar HTML + PHP, banco de dados, entre outras coisas. Nesse tipo de coisa é muito fácil de cometer erros, principalmente se o usuário for inexperiente.
É importante estudar muito, acompanhar os novos recursos e buscar conhecimento em fontes sérias. Só assim evita-se dor de cabeça ou mesmo a perda de espaço no mercado de trabalho.

2.6 Falha no Hardware
E por último, erros também acontecem independente do sistema estar perfeito ou não. Pode ser que o servidor esteja em manutenção, ou outros problemas relacionados a hardware etc. Por esse motivo que, mesmo você fazendo um ótimo tratamento de erros, o sistema não conseguirá ser executado. Falarei de exceções logo mais à frente.


3. Como debugar um script

Para testar um script e ver se ele está funcionando corretamente, há várias maneiras. A primeira delas é testar num servidor local. Para desenvolver, sempre deixe essas opções configuradas no php.ini:

  • [*]display_errors = On [*]display_startup_errors = On [*]error_reporting = E_ALL [*]log_errors = On [*]track_errors = On [*]register_globals = Off

Via script você pode fazer assim:

<?php@ini_set("display_errors", 1);@ini_set("log_errors", 1);@ini_set("error_reporting", E_ALL);?>


Em versões do PHP igual ou anterior à 4.2.3 era possível setar a diretiva register_globals via script, mas agora só via PHP.INI ou .htaccess. Via .htaccess é assim:

 

 

php_flag register_globals off


Agora, com tudo preparado, só resta testar o sistema. Existem vários editores com recursos para debugar um script, como por exemplo o PHPEdit da WaterProof, o editor da Zend ou o da Maguma.


4 - Validações para evitar erros

Um bom tratamento de erros precisa prever vários tipos de erros e, pra isso, existem funções específicas, como por exemplo:

 

 

  • [*]
file_exists - serve para verificar se um arquivo existe [*]defined - serve para verificar se uma constante foi definida. [*]isset - verifica se uma variável existe. [*]is_array - verifica se a variável é um array [*]is_resource - verifica se a variável é um resource [*]is_numeric - verifica se a variável é um número ou uma string numérica. [*]is_uploaded_file - verifica se o arquivo foi uploaded via HTTP POST. [*]is_writable - verifica se pode escrever para o arquivo (writable). [*]version_compare - Compara a versão do php. [*]extension_loaded - verifica se a extensão foi habilitada.

Com essas funções você pode testar, por exemplo, se um arquivo existe, antes de incluí-lo. Caso não exista, você pára o script e dá um aviso para o usuário. Outro exemplo: antes de gravar um arquivo texto, você verifica se ele pode ser escrito, ou antes de usar uma variável teste, se ela existe com isset()
Outra validação muito importante é validar se o formulário foi enviado, assim evitando erro, por exemplo:

Exemplo 4.1 Verificando se um formulário foi enviado

if (getenv("REQUEST_METHOD") == "POST") {	//...faça tal coisa}


Se for get só mudar para GET, assim você testa se o formulário foi enviado.
Outra dica importante é testar se a variável existe caso venha de algum formulário:

Exemplo 4.2 Verificando se uma variável foi inicializada

 

$campo = isset($_POST["campo"]) ? $_POST["campo"] : "";


Exemplo 4.2 Incluindo um arquivo sem verificação
De tratamento de erros:

 

 

<?phprequire "arquivo.php";?>


Mas e se o arquivo nao existir? Iria dar erro, então o mais correto é:

Exemplo 4.3 Incluindo um arquivo com verificação

 

 

<?phpif (file_exists("arquivo.php")) {	require "arquivo.php";}?>


Exemplo 4.4 Desabilitando magic_quotes
Programar dependente de magic_quotes não é recomendando, visto que o site ou sistema poderá não funcionar corretamente caso seja hospedado em um servidor com configuração divergente da que foi adotada para os testes locais. Os erros mais comuns são na inserção de valores em um banco de dados. Além disso, a partir do PHP 6, a diretiva magic_quotes_gpc não existirá mais e, por isso, é recomendado programar desabilitando este recurso. Esta diretiva não pode ser alterada através da função ini_set, devendo ser configurada diretamente no PHP.INI ou, se também possível, através do .htaccess, da seguinte forma:

 

 

php_flag magic_quotes_gpc Off


Como alternativa, você pode utilizar a função abaixo:

 

 

 

function remove_magic_quotes() {	if (get_magic_quotes_gpc()) {		$_GET = array_map("remove_mq", $_GET);		$_POST = array_map("remove_mq", $_POST);		$_REQUEST = array_map("remove_mq", $_REQUEST);		$_COOKIE = array_map("remove_mq", $_COOKIE);	}}function remove_magic_quotes(&$var) {	return is_array($var) ? array_map("remove_magic_quotes", $var) : stripslashes($var);}


Basicamente, a função verifica se a diretiva magic_quotes está habilitada e, então, varre pelos dados dos arrays globais inicializados (enviados por um formulário, por exemplo), eliminando os escapes dos caracteres. Preferencialmente, esta função deve ser chamada num arquivo de inicialização do sistema ou site.


5. Tratando erros com Exceções

A partir da versão 5 do PHP, pode-se tratar erros usando Exceções. Com o uso desse recurso, podemos manipular os erros com mais precisão, facilitando, por exemplo, a criação de um log de erros contendo o nome do arquivo e a linha em que o erro ocorreu.
A classe Exception pode ser extendida a uma outra, viabilizando a personalização de mensagens de erro e a criação de uma classe para cada tipo de exceção. Por exemplo: é possível termos uma classe para manipular erros relacionados a banco de dados, outra para o manuseio de arquivos, de imagens, etc.

Uma exceção deve ser disparada (thrown) dentro de um bloco try{}. Em seguida, deve ser pega (catched) usando o bloco catch{}.

Exemplo 5.1: Usando exceções para capturar um possível erro na conexão com um banco de dados MySQL

 

 

 

try {	//usamos o arroba para ocultar o possível erro retornado pelo PHP	@$MySQLi = new MySQLi("localhost", "user", "pass", "db_name");		if (!$MySQLi) { //se conexão falhar		throw new Exception("Erro ao realizar a conexão com o banco de dados");	}}catch (Exception $e) {	echo $e->getMessage();	exit;}


Se a conexão falhar, será disparada uma exceção, que será, posteriormente, pega no seu bloco catch correspondente. Nesse bloco, devemos colocar o nome da classe de exceção utilizada e criar uma variável, a qual será uma instância da exceção.

Para obter mais informações sobre exceções, veja o link abaixo:
http://www.php.net/manual/pt_BR/language.exceptions.php


Colaboraram neste artigo:
Anderson Mello
Beraldo
Fabyo

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

adorei este artigo , estou estudando php e com esta dica ja faço as coisas certasabraço!!!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Recomendo deixar error_reporting(E_ALL), para mostrar todos os tipos de erros.

Em fase de desenvolvimento,fora dela...eu curto dar o minimo de informações possiveis ao usuário (evitar que conheça as tecnologias usadas e etc).

Podiam ter falado um pouco sobre o(s) trigger_error(s),error_handler(s) e exceções personalizadas que ficava perfeito!!!

Matéria muito boa (clara,objetiva e completa),os 3 fizeram um ótimo trabalho!

Abraços!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Recomendo deixar error_reporting(E_ALL), para mostrar todos os tipos de erros.

Em fase de desenvolvimento,fora dela...eu curto dar o minimo de informações possiveis ao usuário (evitar que conheça as tecnologias usadas e etc).

Podiam ter falado um pouco sobre o(s) trigger_error(s),error_handler(s) e exceções personalizadas que ficava perfeito!!!

Matéria muito boa (clara,objetiva e completa),os 3 fizeram um ótimo trabalho!

Abraços!

Em fase de desenvolvimento, todas ass mensagens de erro devem ser exibidas, claro. Após a conclusão, basta modificar display_errors para 0 e nenhum possível erro será exibido. É sempre bom criar mensagens de erro mais "amigáveis" para serem exibidas, que apenas alertem sobre o erro, sem mostrar tecnologia usada, estrutura de diretórios etc.

 

Realmente não demos muita ênfase a Exceções... essa parte ficou meio fraca.

Também poderíamos ter falado de ogs de erro...

São muitas coisas. Difícil abranger muitas delas num único artigo. Quem sabe, logo haverá algum material sobre isso mais detalhado por aqui. http://forum.imasters.com.br/public/style_emoticons/default/thumbsup.gif

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom dia companheiros, tenho que discordar de alguns pontos..

 

O uso correto do Exception é pra você tomar outro rumo no codigo, pelo menos isso no meu entendimento, afinal o nome mesmo diz (se acontecer alguma coisa, VOU LANÇAR UMA EXCEÇÃO AO CODIGO)

 

Vamos usar o exemplo do database mesmo, você tenta fazer a conexao no 192.168.1.1... porém essa base está fora do ar.. logo você lança um catch pra tentar fazer a conexão por outro database 192.168.1.2 (que seria um backup ou uma copia do database em um servidor mais lento) e juntamente com essa Exceção você loga o erro (conforme nosso amigo explicou no codigo).. um tratamento de erros no PHP é feito através do set_error_handler e do trigger_error, sao funcoes especificas para o tratamento de erro desde a versao 4 do PHP...

 

Uma outra coisa que eu nao faria de forma alguma seria essa funcao que voce usou no exemplo 4.3

 

<?php

if (file_exists("arquivo.php")) {

require "arquivo.php";

}

?>

 

a partir do momento que voce da um REQUIRE em um arquivo, significa que ele eh essencial para o funcionamento do software, caso contrario, usa-se include...

 

abracos

Compartilhar este post


Link para o post
Compartilhar em outros sites

O uso correto do Exception é pra você tomar outro rumo no codigo, pelo menos isso no meu entendimento, afinal o nome mesmo diz (se acontecer alguma coisa, VOU LANÇAR UMA EXCEÇÃO AO CODIGO)

 

Vamos usar o exemplo do database mesmo, você tenta fazer a conexao no 192.168.1.1... porém essa base está fora do ar.. logo você lança um catch pra tentar fazer a conexão por outro database 192.168.1.2 (que seria um backup ou uma copia do database em um servidor mais lento) e juntamente com essa Exceção você loga o erro (conforme nosso amigo explicou no codigo).. um tratamento de erros no PHP é feito através do set_error_handler e do trigger_error, sao funcoes especificas para o tratamento de erro desde a versao 4 do PHP...

Concordo com você.

O conceito de exceção pode variar conforme o sistema. Supondo que não há um segundo servidor de banco de dados para se conectar, não há o que fazer a não ser encerrar a execução e mostrar uma mensagem ao usuário.

E, como o próprio nome diz, Exception não é para tratar qualquer erro. Para isso há as funções citadas por você. Serve para tratar erros que são "exceção", ou seja, que ocorrem por um falha momentânea no servidor, por exemplo.

 

 

Uma outra coisa que eu nao faria de forma alguma seria essa funcao que voce usou no exemplo 4.3

 

<?php

if (file_exists("arquivo.php")) {

require "arquivo.php";

}

?>

 

a partir do momento que voce da um REQUIRE em um arquivo, significa que ele eh essencial para o funcionamento do software, caso contrario, usa-se include...

O exemplo foi só para ilustrar como fazer um require sem gerar erro do PHP. O ideal é colocar um else ali, para encerrar a execução.

 

 

 

Agradecemos a contribuição http://forum.imasters.com.br/public/style_emoticons/default/thumbsup.gif

Compartilhar este post


Link para o post
Compartilhar em outros sites

Além disso devemos utilizar algum programinha para Debug como Xdebug ou mesmo o Firebug que se estende ao Firefox.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Além disso devemos utilizar algum programinha para Debug como Xdebug ou mesmo o Firebug que se estende ao Firefox.

 

Discordo, não é preciso utilizar programa algum, à parte. O próprio debug do PHP é excelente e bem explicativo basta interpretá-lo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

mto bom artigo !

parabens...

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.