PHP – Criando e tratando exceptions

1

Category : PHP

 

Não é novidade, mas vale o registro. O PHP 5, possui uma funcionalidade bem interessante, similar a outras linguagens orientadas a objeto, Exceção. Quando algo altera o fluxo de execução do sistema ele dispara uma Exceção. Uma exceção pode ser disparada ou capturada, depende do que você pretende. Você pode customizar um série de tratamentos de erros que irão facilitar o desenvolvimento do seu sistema, com essa custimização você pode saber exatamente o que está sendo tratado e se algo fugir desse controle é algo anormal e fica mais facil a rastreabilidade.

Dentro de uma exceção, você pode disparar um log, ou um alert, ou registrar algo no banco, é um fluxo de erro sob controle.

Eu costumo tratar as exceções para tudo, campo em branco, tipo de dado inválido, e-mail inválido, ou se alguma fórmula não foi validada. Para isso uso um conjunto de classes que constituem as mensagens e os testes para que as exceções sejam disparadas:

Uma classe Main para controlar as requisições de Exception:

MainException.php:

<?PHP
    /**
    * Declaração da classe para tratamento de erros
    * A classe deve ser extendida da classe Exception do PHP
    * Ela irá realizar a sobrescrita da classe Exception do PHP
    */
    class MainException extends Exception {
        //Faço a declaração das variávis que vou utilizar no corpo da classe
        private    $cod          = 0;
        private    $msg          = "";
        private    $erromsg      = "";

        /**
        * Aqui faço a declaração do método construtor de classe
        * Esse método recebe os seguintes parametros:
        * @param $cod – Código de erro
        * @param $msg – Uma mensagem de erro personalizada
        * @param $erromsg – Uma mensagem de erro padrão
        */

        public function __construct( $cod = 0 , $msg = "" , $erromsg = "" ) {
 
            //Sobreescrevo as propiedades da classe passando os parametros
            $this->cod = $cod;
            $this->msg = "Ocorreu um erro não identificado";
            $this->erromsg = $erromsg;
 
            //Aqui eu chamo o construtor da classe pai 
            parent::__construct( $this->msg , $this->cod );        
 
        }
 
 
        /**
        * Este método irá salvar nossos erros em um log
        */
        public function _Log() {

            //Define o arquivo que será criado ou gravado caso exista, o nome do arquivo irá ser o nome da classe
 
            $log = __CLASS__ . "_log_" . date("dmY") . "txt";
 
            //Se não existe arquivo, cria
            if( !file_exists($log)){
 
                $msg = "/************************************************** " .
                " * Arquivo de log " .
                " * " .
                " * ClassName: " . __CLASS__ . " " .
                " * Data Criação: " . date("d/m/Y H:i") . " " .
                " *************************************************/ " .
                "——————————————————————- ";
 
            }else
                $msg = "";
 
                //Abre o arquivo
                if($fp = fopen( $txt , "a+")) {
 
                //Arquivo
                $msg .=    __CLASS__ . " hora: ".date("H:i") . " " .
                "Erro [ {$this->cod} ]: linha ( {$this->line} ) " .
                "{$this->msg} " .
                "{$this->erromsg} " .
                "——————————————————————- ";
 
                //Grava
                fwrite($fp, $msg);
                fclose($fp);
            }
 
        }
 
    }
?>

A classe abaixo estende MainException e a customiza para Exceções de texto:

textException.php:

<?PHP
/**
 * Esta classe é responsável por disparar exceções relacionadas a texto
 */
 class textException extends MainException {
 
      public function __construct(  ) {
          //Sobrescrita do construtor de MainException, com os valores que queremos
          parent::__construct( 1, "Tipo de caracter inválido", PHPSELF);
         
          $this->_Log();
                       
      }
          
 }
?>

A classe abaixo faz a verificação do texto e dispara a exceção:

verificaTexto.php:

<?PHP
 
class verificaTexto
{
    public function __construct($texto)
    {
        if(!is_int($texto))
        {
            echo $texto;
        }
        else
        {
            throw new textException();
        }
    }
 
}
 
?>

A classe abaixo faz o teste para números e caso falhe, dispara MainException, ou seja sem customizar o tipo de exceção que será disparada, então irá enviar a mensagem padrão:

verificaValor.php:

<?PHP
 
class verificaValor
{
    public function __construct($val)
    {
        if($val == 1)
        {
            echo $val;
        }
        else
        {
            throw new MainException();
        }
    }
 
}
 
?>

Apenas para teste:

<?PHP
 
include ("autoload.php");
 
try
{
 
    //$b = new verificaTexto(1);
    $b1 = new verificaValor(1123);
 
}
Catch(textException $te)
{
    echo $te->getMessage();
}
catch(Exception $e)
{
    echo $e->getMessage();
}
 
 
?>

E o autoload se alguém quiser:

<?PHP
 
function __autoload($class_name) {
    require_once $class_name . ‘.php’;
}
 
?>

Como podem ver, a classe MainException é que faz todo o trabalho, nela temos o método principal que realiza o disparo das exceptions, em textException, sobrespcrevemos a classe MainException e fazemos ela se comportar como queremos para disparar apenas uma mensagem de erro para textos.

Ainda existe a possibilidade de disparar uma Exception genérica, caso nosso tratamento não seja para textos. Se observarem com calma verão que se trata apenas de sobrescritas de métodos algo que seria perfeitamente possível sem Exception, porém desta forma temos mais controle (fora a elegancia do código).

Bom é isso, qualquer dúvida comentem.

Para saber mais:

Tags BlogBlogs: php, exception, oo

 

PDO e BEAN no PHP

3

Category : PHP

PDO é uma extensão nativa no PHP a partir dar versão 5.1, com ela conseguimos trabalhar com diversos bancos de dados sem precisar alterar as as querys feitas (claro que devemos usar SQL ANSI para isso). Para os acostumados com ADODB ou MDB2, o PDO é um facilitador e tanto, pois é nativo do PHP e trabalha a uma velocidade muito superior à essas duas classes.

Implementa cache de query em nível de código (o mesmo que o bind do oracle) e permite uma flexibilidade na manipulação dos resultados tanto como arrays ou objetos.

Por se tratar de uma feature relativamente nova, ela não esta completamente finalizada pelo time do PHP e algumas funções estão disponíveis apenas no cvs.

Um pequeno exemplo de como utilizar o PDO:

1
2
3
4
5
6
7
8
prepare("select contenttype, imagedata from images where id=?");
  $stmt-&gt;execute(array($_GET['id']));
  $stmt-&gt;bindColumn(1, $type, PDO::PARAM_STR, 256);
  $stmt-&gt;bindColumn(2, $lob, PDO::PARAM_LOB);
  $stmt-&gt;fetch(PDO::FETCH_BOUND);
 
  header("Content-Type: $type");
?&gt;

Eu tenho utilizado PDO com grande sucesso em meus projetos e cada vez mais me acostumo a utiliza-la no lugar de ADODB/MDB2, tenho trabalhado 100% orientado a objetos no padrão BEAN igual ao do java (gosto de manter os dados protegidos dentro do meu código).

Abaixo um pequeno exemplo de como utilizao PDO em meus projetos. O código está comentado, porém se surgirem dúvidas me mande um e-mail ou comente abaixo que eu dou uma força.

Conexao.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
persistencia = true; }
  }
 
  public function getConnection(){
    try{
      $this-&gt;con = new PDO(
          $this-&gt;dbType.":host=".$this-&gt;host.";
          dbname=".$this-&gt;db,$this-&gt;user,
          $this-&gt;pass,
          array(PDO::ATTR_PERSISTENT=&gt; $this-&gt;persistencia)
          );
 
      /*ESTA PROPRIEDADE INDICA COMO O PDO VAI RETORNAR OS
        ERROS SQL NO MODO PDO::ERRMODE_WARNING O RETORNO DO
        ERRO É IGUAL AO QUE VEMOS SEM A UTILIZAÇÃO DO PDO*/
    $this-&gt;con-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
      return $this-&gt;con;
    }catch(PDOException $ex){
      echo "ERRO:".$ex-&gt;getMessage();
    }
  }
 
  public function Close(){
    if($this-&gt;con != NULL){
      $this-&gt;con = NULL;
    }
  }
}
?&gt;

cliente.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
id_cliente = $id_cliente;
  }
 
  public function getIdCliente(){
    return $this-&gt;id_cliente;
  }
 
  public function setEmail($email){
    $this-&gt;email = $email;
  }
 
  public function getEmail(){
    return $this-&gt;email;
  }
 
  public function setTelefone($telefone){
    $this-&gt;telefone = $telefone;
  }
 
  public function getTelefone(){
    return $this-&gt;telefone;
  }
}
?&gt;

clienteModel.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
con = Conexao::getConnection();
  }  
 
  public function Insert($cliente){
    $query = "insert into cliente (id_cliente, nome, email, telefone)
	          values (:id_cliente,:nome,:email,:telefone)";
    try{
      $stmt = $this-&gt;con-&gt;prepare($query);
      $stmt-&gt;bindValue(':id_cliente',$cliente-&gt;getIdCliente());
      $stmt-&gt;bindValue(':nome',$cliente-&gt;getNome());
      $stmt-&gt;bindValue(':email',$cliente-&gt;getEmail());
      $stmt-&gt;bindValue(':telefone',$cliente-&gt;getTelefone());
      return $stmt-&gt;execute();
    }catch(PDOException $ex){
      echo $ex-&gt;getMessage();
    }
  }
 
  public function Update($cliente){
    $query = "update users set nome=:nome, email=:email,
	          telefone=:telefone where id_cliente=:id_cliente";
    try{
      $stmt = $this-&gt;con-&gt;prepare($query);
      $stmt-&gt;bindValue(':nome',$user-&gt;getNome());
      $stmt-&gt;bindValue(':email',$user-&gt;getEmail());
      $stmt-&gt;bindValue(':telefone',$user-&gt;getTelefone());
      $stmt-&gt;bindValue(':id_cliente',$user-&gt;getIdCliente());
      $stmt-&gt;execute();
    }catch(PDOException $ex){
      echo $ex-&gt;getMessage();
    }
  }
 
  public function Select($query = NULL){
 
    if(trim($query) == NULL){
      $query = "select * from clientes";
      try{
        $stmt = $this-&gt;con-&gt;prepare($query);
        $stmt-&gt;execute();
 
        /*
          ESSE AQUI É O PULO DO GATO: fetchObject(nome_da_classe)
          COM fetchObject COLOCAMOS O RETORNO DO BANCO DE DADOS EM
		  UMA CLASSE COM O NOME ESPECIFICADO NO PARAMETRO
          NO ARQUIVO EM QUE UTILIZAMOS A CONSULTA, TEMOS UM INCLUDE
		  DO ARQUIVO cliente.php QUE POSSUI A DEFINIÇÃO
          DA CLASSE cliente. LOGO, QUANDO A QUERY FOR EXECUTADA,
		  TEREMOS COMO RETORNO UMA CLASSE cliente COM TODOS OS
          ATRIBUTOS PREENCHIDOS PODENDO UTILIZAR OS SET´S E GET´S AUTOMATICAMENTE.
        */
 
        $stmt-&gt;fetchObject('cliente');
 
      }catch(PDOException $ex){
        echo $ex-&gt;getMessage();
      }
    }else{
      try{
        $stmt = $this-&gt;con-&gt;prepare($query);
        $stmt-&gt;setFetchMode(PDO::FETCH_CLASS, 'cliente');
        $stmt-&gt;execute();
 
        /*
          AQUI TEMOS UMA IMPLEMENTAÇÃO DIFERENTE, NÃO TEMOS COMO GARANTIR QUE
		  A QUERY PASSADA RETORNARÁ EXATAMENTE OS ATRIBUTOS DA CLASSE cliente,
		  PORTANTO, SETAMOS O RETORNO PARA A CLASSE cliente, SE O RESULTADO
		  PREENCHER OS ATRIBUTOS, TEREMOS UMA CLASSE cliente COM OS
		  ATRIBUTOS PREENCHIDOS E PODENDO SER MANIPULADA PELOS GET´S E SET´S
		  CASO NÃO, ELE RETORNA UMA CLASSE ONDE OS DADOS PODEM SER
		  ACESSADOS COMO ATRIBUTOS.
        */
 
      return $users = $stmt-&gt;fetch(PDO::FETCH_CLASS);  
 
      }catch(PDOException $ex){
        echo $ex-&gt;getMessage();
      }
    }
  }
}
?&gt;

operacao.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
clienteValid();
 
  //CONSULTA
 
  $query = "select * from cliente where id_cliente=".$_REQUEST['cliente'];
  $cliente = $clienteModel-&gt;Select($query);
 
  echo $cliente-&gt;getNome();
  echo $cliente-&gt;getEmail();
 
  //ATUALIZAÇÃO
 
  $cliente-&gt;setIdCliente($cliente-&gt;getIdCliente());
  $cliente-&gt;setNome($cliente-&gt;getNome());
  $cliente-&gt;setEmail($cliente-&gt;getEmail());
  $cliente-&gt;setTelefone($_REQUEST['telefone']);
 
  $clienteModel-&gt;Update($cliente);
 
  //INSERT
 
  $cliente-&gt;setNome($_REQUEST['nome']);
  $cliente-&gt;setEmail($_REQUEST['email']);
  $cliente-&gt;setTelefone($_REQUEST['telefone']);
 
  $clienteModel-&gt;Insert($cliente);
?&gt;

Este código é bem simples, mas é o que tenho utilizado, ele vêm evoluindo com o tmepo, e para minhas necessidades é bem eficiente. O PDO2 está por vir e promente melhorar muito toda essa interface e suporte a outra bancos.

Algumas referências que me ajudaram a entender a utilização do PDO:

Qualquer sugestão me mande, ainda estou aprendendo a trabalhar com PDO.

Edit

Conforme as observações do Dimas Gomez, acertei o código exibido e aproveito para disponibilizar os fontes aqui.

Quanto ao erro “could not find driver” você pode deve habilitar o driver para seu banco de dados em seu php.ini. Como fazer isso está bem descrito no manual do php em http://php.net/pdo.

Tags BlogBlogs: php, pdo, php5, oo