+19

Desmistificando o PDO - PHP Data Object

criado por Rubens Takiguti Ribeiro em 16/12/2009 12:38am
Como utilizar PDO?

Para utilizar PDO, primeiro é instanciado um objeto da classe PDO, que representa a conexão com um banco. No construtor da classe, deve ser informado o chamado "DSN", que é uma string de conexão semelhante àquela vista anteriormente na função de conexão com PostgreSQL. Cada driver PDO especifica uma forma de como é montado o DSN para o SGBD correspondente. Além do DSN, também é informado, por parâmetro, o usuário, a senha de acesso e as opções adicionais.

// Exemplo de conexao com MySQL via PDO
$dsn = 'mysql:host=host;port=3306;dbname=bd';
$usuario = 'usuario';
$senha = 'senha';
$opcoes = array(
    PDO::ATTR_PERSISTENT => true,
    PDO::ATTR_CASE => PDO::CASE_LOWER
);

try {
    $pdo = new PDO($dsn, $usuario, $senha, $opcoes);
} catch (PDOException $e) {
    echo 'Erro: '.$e->getMessage();
}

Após abrir uma conexão, as consultas podem ser feitas de duas maneiras:
1 - Através da própria conexão, com o método "exec" ou o "query";
2 - Montando uma prepared statement com o método "prepare", que devolve um objeto da classe PDOStatement, e depois executando o método "execute" (desta classe).

O método "query" é utilizado para consultas que retornam resultados tabulares (como o SELECT) e devolve um objeto da classe PDOStatement com o resultado. Já o método "exec" é utilizado para consultas que não retornam resultados tabulares (como o INSERT, UPDATE, DELETE) e retorna apenas o número de linhas afetadas.

Estes métodos são úteis para executar consultas fixas (não-variáveis). Afinal, se envolvessem valores recebidos do usuário, estes valores precisariam ser escapados através do método "quote" (para evitar falhas de segurança com SQL Injection).

Já o método "prepare" é útil para montar uma consulta com dados variáveis. É possível especificar uma SQL com pontos de substituição que, ao serem substituidos, são escapados pela classe automaticamente. Vejamos alguns exemplos:

// Usando "exec"
$inseriu = $pdo->exec('INSERT INTO logs (operacao) VALUES (1)');
$ultimo_id = $pdo->lastInsertId();

// Usando "query"
$stmt = $pdo->query('SELECT nome, login FROM usuarios');

// Percorrento um resultset com while
while ($obj = $stmt->fetchObject()) {
    ...
}

// Percorrendo um resultset com foreach
foreach ($stmt as $linha) {
    ...
}

Note que a classe PDOStatement (objeto $stmt) implementa a interface Traversable, indicando que ela pode ser percorrida por uma estrutura "foreach".

Existem diferentes formas de se executar uma prepared statement com PDO:
// 1 - Usando "?" nos pontos-chave
$stmt = $pdo->prepare('INSERT INTO usuarios (nome, login) VALUES (?,?)');

// Passando os valores a serem usados no primeiro e segundo "?"
$dados = array('Rubens', 'rubens');
$consultou = $stmt->execute($dados);

// 2 - Usando pontos-chave nomeados
$stmt = $pdo->prepare('INSERT INTO usuarios (nome, login) VALUES (:nome, :login)');

// Passando os valores a serem usados em :nome e :login
array(':nome' => 'Rubens', ':login' => 'rubens');
$consultou = $stmt->execute($dados);

// 3 - Fazendo binding de parametros
$stmt = $pdo->prepare('INSERT INTO usuarios (nome, login) VALUES (:nome, :login)');

// Fazendo o binding
$nome = 'Rubens';
$login = 'rubens';
$stmt->bindParam(':nome', $nome, PDO::PARAM_STR, 128);
$stmt->bindParam(':login', $login, PDO::PARAM_STR, 20);

// Executando a SQL com os valores definidos com binding
$consultou = $stmt->execute();

Prepared statements tendem a ser mais rápidas que as consultas convensionais, já que a consulta fica previamente "compilada" e pronta para execução com novos valores. Ao invés do SGBD interpretar toda a SQL, ele apenas atribui novos valores aos pontos chave e realiza a operação. Funcionalidade muito útil para inserções ou atualizações em massa em uma tabela.

Comentários:

Mostrando 1 - 10 de 22 comentários
empalamado disse:
//Códigos em PDO pra conectar com o banco sem erro
//No espaço com ... você deve colocar o nome do seu banco de dados
//----------------------------------------------------------------------
try{
$pdo=new PDO("mysql:host=localhost;dbname=....","root"."");
} catch(PDOException $e){
echo $e->getMessage();
}

//----------------------------------------------------------------------
02/11/2015 6:45am (~2 anos atrás)

Diego,
Uma opção é abrir uma conexão separada para cada banco.
Outra opção é usar o comando "USE" (do MySQL):
$pdo->query('use nomebanco');
01/07/2013 7:18am (~5 anos atrás)

Diego disse:
Olá amigos
estou começando a usar o PDO, estou tentando
selecionar outro banco de dados depois da conexão estabelecida
com mysql simples se usa "mysql_select_db()" mas no pdo não sei como fazer isso
se alguém puder me ajudar agradeço
29/06/2013 7:23pm (~5 anos atrás)

Ola pessoal, estou estudando o PDO e definitivamente não sei como pude sobreviver sem ele... hehe.. Porém visão explorar os recursos de orientação a objetos criei um método usando que me retorna o resultado de uma busca que posso reaproveitar na minha aplicação (return self::conn()->query($querySelect);). Até ai blza, consigo varrer o retorno com um forearch e fica tudo certo. Mas pretendo utilizar esse array para preencher uma combo, e caso não haja resultado alterar o valor da mesma informando a aunsência de dados... Alguma sugestão ??
08/10/2012 6:16pm (~6 anos atrás)

Wesley, o método "bind" serve para ligar uma variável a uma query. Com isso, qualquer mudança na variável implica na mudança da query. Não tem problema em definir o valor antes ou depois. A única coisa que você precisa estar atento é em chamar o método "execute" após já ter feito o bind e colocado o valor desejado.
31/07/2012 9:00am (~6 anos atrás)

Wesley Bastos disse:
Rubens,
parabéns,

Tenho uma dúvida. Na documentação oficial do PHP, o exemplo faz o bind dos parâmetros antes de atribuir as variáveis (copiado abaixo). Você fez antes. Tem diferença?

-----------------------------------------------------
(http://www.php.net/manual/en/pdo.prepared-statements.php):

<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
-------------------------------------------------------------
30/07/2012 10:30pm (~6 anos atrás)

bradock disse:
ola a todos! alguem poderia me explicar se o uso de metodo como fiz no CUD esta errado no sentido de ser perigoso, e se utilizar assim inutiliza o metodo privado uma vez q a sql esta sendo feita toda em um array e no outro executando?

se nao for pedir demais aponte o certo e errado, corro riscos assim?

e utilizar return em um metodo e errado? {return self::metodo();}

final class Tools
{

private static $query;

final private static function sql($sql,$execute)
{self::$query=BD::conn()->prepare($sql);self::$query->execute($execute);}

final public function CUD($sql,$execute)
{self::sql($sql,$execute);return self::$query;}
}

grato desde já
30/04/2012 4:22pm (~6 anos atrás)

Muito bom o Post, me ajudou muito.
Para exibir os resultados do while basta

$stmt = $pdo->query('SELECT nome, login FROM usuarios');

// Percorrento um resultset com while
while ($obj = $stmt->fetchObject()) {
$obj->nome; //campo que deseja exibir
}

Abraço!
23/11/2011 11:30am (~6 anos atrás)

Olá, venho aqui recomendar, para quem se interessar o uso de uma classe PDO de conexão, a qual já venho utilizando. Possui um repositório no github para poder baixar e utilizar em suas aplicações, ou simplesmente acompanhar e/ou compartilhar.

Segue link: http://bitly.com/PDO4You

Sugestões ou críticas, sempre são bem vindas e ajudam a tornar esta classe ainda melhor para benefício de todos e assim seja até quando o PHP existir. =D

Abraços.
30/07/2011 10:15pm (~7 anos atrás)

Jairo disse:
Rubens, obrigado pela resposta. Pensei que dava pra fazer algo como isto, ou seja, selecionar quais colunas retornar da consulta, mas pelo jeito devo fazer isso de outra forma.

quando tento iterar o objeto PDOStatement aparece algo como:

array
'?' => string 'telefone' (length=8)
0 => string 'nome' (length=4)
1 => string 'endereco' (length=8)
2 => string 'telefone' (length=8)

26/03/2011 12:58pm (~7 anos atrás)

Novo Comentário:

(Você pode usar tags como <b>, <i> ou <code>. URLs serão convertidas para links automaticamente.)