Modificando o controle de erros do PDO

Artigo que explica como modificar o controle de erros do PHP para que utilizem erros, exceptions (exceções) ou nada.

A classe PDO permite que seja modificada a estratégia para controle de erros ocorridos. As possibilidade são:

  • Obter os erros via métodos errorCode e errorInfo;
  • Emitir WARNING nos logs; ou
  • Emitir uma exceção (PDOEexception).

Para configurar isso, basta utilizar o método setAttribute, informando o valor desejado para o atributo de configuração PDO::ATTR_ERRMODE, que pode receber um dos seguintes valores:

  • PDO::ERRMODE_SILENT - para obter os erros via errorCode e errorInfo;
  • PDO::ERRMODE_WARNING - para emitir WARNING; ou
  • PDO::ERRMODE_EXCEPTION: - para emitir exceções.

Veja um exemplo de uso para obter os erros via errorInfo:

...
try {
    $pdo = new PDO($dsn, $usuario, $senha);
} catch (PDOException $e) {
    exit(1);
}
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);

$sql = 'SELETC id FROM usuarios';
$stmt = $pdo->query($sql);
if (!$stmt) {
    list($erro, $erro_driver, $mensagem_driver) = $pdo->errorInfo();
    switch ($erro) {
    case '42000':
        trigger_error('Erro de sintaxe na SQL: '.$sql, E_USER_ERROR);
        exit(1);
    ...
    }
}

O valor devolvido por errorInfo é um array com três posições: uma com o código SQLSTATE, previsto na ANSI SQL, outra com o código devolvido pelo driver usado, e a última com a mensagem devolvida pelo driver. O erro "42000" indica um erro de sintaxe. Como colocamos propositalmente um erro de sintaxe na nossa SQL, iremos detectá-lo pelo código SQLSTATE.

Para capturar o mesmo erro, mas com uso de exceções, o código ficaria assim:

...
try {
    $pdo = new PDO($dsn, $usuario, $senha);
} catch (PDOException $e) {
    exit(1);
}
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$sql = 'SELETC id FROM usuarios';
try {
    $stmt = $pdo->query($sql);
} catch (PDOException $e) {
    switch ($e->errorInfo[0]) { 
    case '42000':
        trigger_error('Erro de sintaxe na SQL: '.$sql, E_USER_ERROR);
        exit(1);
    ...
    }
}

O atributo errorInfo é um array igual ao devolvido pelo método errorInfo da classe PDO, porém, a classe PDOException também tem outros métodos úteis como:

  • getCode - Para obter a SQLSTATE do erro;
  • getMessage - Para obter a mensagem específica do driver;
  • getFile - Para obter o erro em que ocorreu a exceção;
  • getLine - Para obter a linha em que ocorreu a exceção;
  • getTrace - Para obter as chamadas de código até chegar ao arquivo com erro.


Observação: para criar o objeto PDO (chamada do construtor), é obrigatório utilizar o tratamento via exceções, pois só depois que o objeto foi criado é que podemos chamar o método setAttribute.

Por padrão, a classe PDO usa PDO::ERRMODE_SILENT, mas, especificamente para o construtor, emite sempre uma exceção em caso de falha com a DSN ou com a conexão.

8 comentários

Anônimo disse...

ae brother, estou criando uma rede social, porém estou com um erro que não consigo resolver, se você puder me ajudar, o erro é esse Fatal error: Call to a member function prepare() on a non-object in /home/u450708226/public_html/redesocial/cadastro.php on line 45
meu código :
prepare("SELECT `id` FROM `usuarios` WHERE `email`=?");
if($verificar->execute(array($email))){
if($verificar->rowCount()>=1){
echo 'Este e-mail já está cadastrado em nosso sistema!';
}elseif($senha=='' OR strlen($senha)<4){
echo 'Sua senha tem que ter mais de 4 caracteres!';
}elseif(strtolower($captcha) <> strtolower($_SESSION['captchaCadastro'])){
echo 'O código digitado não corresponde com a imagem!';
}else{

$nascimento = "$ano-$mes-$dia";

$inserir = DB::getConn()->prepare("INSERT INTO `usuarios` SET `email`=?, `senha`=?, `nome`=?, `sobrenome`=?, `sexo`=?, `nascimento`=?");

if($inserir->execute($email,$senha,$nome,$sobrenome,$sexo,$nascimento)){
header('Location: ./');
}
}
}
}
}
?>

Anônimo disse...

o erro está na seguinte linha

$verificar = DB::getConn()->prepare("SELECT `id` FROM `usuarios` WHERE `email`=?");

Rubens Takiguti Ribeiro (autor do blog) disse...

Olá, Anônimo,

Parece que o problema é que o método getConn deveria devolver um objeto da classe PDO, mas não está. Confira para ver se incluiu o "return" corretamente.

Anônimo disse...

Olá Rubens, não entendi muito bem oque você quiz dizer, vou postar novamente meu código, se puder postar um comentário com o jeito certo, eu ficaria muito grato.
DB.class.php

Anônimo disse...


class DB{
private static $conn;
static function getConn(){
if(is_null(self::$conn)){
self::$conn = new PDO('mysql:host=mysql.hostinger.com.br;dbname=u450708226_humor','u450708226_humor','lampadas');
}
}
}

Anônimo disse...

Código do formulario

if(isset($_SERVER['REQUEST_METHOD']) AND $_SERVER['REQUEST_METHOD'] == 'POST'){
extract($_POST);
if($nome == '' OR strlen($nome)<4){
echo 'Escreva seu nome corretamente!';
}elseif($sobrenome=='' OR strlen($sobrenome)<6){
echo 'Escreva seu sobrenome corretamente!';
}elseif($email==''){
echo 'Escreva seu e-mail!';
}elseif(!preg_match("/^[A-Za-z0-9]+([_.-][A-Za-z0-9]+)*@[A-Za-z0-9]+([_.-][A-Za-z0-9]+)*\\.[A-Za-z0-9]{2,4}$/i",$email)){
echo 'Este e-mail é inválido!';
}else{
include ('classes/DB.class.php');

$verificar = DB::getConn()->prepare("SELECT `id` FROM `usuarios` WHERE `email`=?");
if($verificar->execute(array($email))){
if($verificar->rowCount()>=1){
echo 'Este e-mail já está cadastrado em nosso sistema!';
}elseif($senha=='' OR strlen($senha)<4){
echo 'Sua senha tem que ter mais de 4 caracteres!';
}elseif(strtolower($captcha) <> strtolower($_SESSION['captchaCadastro'])){
echo 'O código digitado não corresponde com a imagem!';
}else{

$nascimento = "$ano-$mes-$dia";

$inserir = DB::getConn()->prepare("INSERT INTO `usuarios` SET `email`=?, `senha`=?, `nome`=?, `sobrenome`=?, `sexo`=?, `nascimento`=?");

if($inserir->execute($email,$senha,$nome,$sobrenome,$sexo,$nascimento)){
header('Location: ./');
}
}
}
}
}