PHP Conectar com PDO
Na aula anterior você viu o que é um banco de dados e como é o SQL. Agora o PHP vai conversar com o banco. Quem faz essa ponte é o PDO (PHP Data Objects, "objetos de dados do PHP"): uma forma única de conectar, mandar SQL e ler respostas, que funciona igual para SQLite, MySQL, PostgreSQL e outros. Nesta aula você vai abrir uma conexão, criar uma tabela, ler os dados de várias formas e entender as mensagens de erro.
- O que é o PDO e o que é um driver.
- Como conectar com
new PDO("sqlite:loja.db")e o que é o DSN. - Por que usar
PDO::ERRMODE_EXCEPTIONe como tratar o erro de conexão. - A diferença entre
exec(comandos) equery(perguntas). - Como ler o resultado com
fetch,fetchAllefetchColumn, e os modosFETCH_ASSOC,FETCH_NUMeFETCH_OBJ.
Os programas foram executados com o PHP 8.5 na máquina fictícia da Ana, na pasta ~/loja. O PDO já vem no PHP; para o SQLite, nada precisa ser instalado. O editor do guia também tem o SQLite, então você pode repetir tudo nas caixas "Experimente".
A ideia: o adaptador de tomada
Quem viaja leva um adaptador universal de tomada: o carregador do celular é sempre o mesmo, e só a pecinha que encaixa na parede muda de país para país. O PDO é esse adaptador:
- O seu código PHP (o carregador) usa sempre os mesmos comandos:
new PDO,query,exec,fetch… - O driver (a pecinha) sabe falar com um banco específico:
pdo_sqlitepara SQLite,pdo_mysqlpara MySQL,pdo_pgsqlpara PostgreSQL.
Para ver quais "pecinhas" o seu PHP tem:
$ php -r 'print_r(PDO::getAvailableDrivers());'
Array
(
[0] => mysql
[1] => pgsql
[2] => sqlite
)
A máquina da Ana tem três. Nesta aula usamos o sqlite; o mysql fica para a aula MySQL e MariaDB.
1. Conectar: new PDO
<?php
$pdo = new PDO("sqlite:loja.db");
echo "Conectado!\n";
var_dump($pdo);
- new PDO(...)
- Cria um objeto PDO: a conexão aberta com o banco. A palavra
newcria objetos (você vai estudá-los em Classes e Objetos; por enquanto, pense no objeto como "a linha telefônica com o banco"). - "sqlite:loja.db"
- O DSN (Data Source Name, "nome da fonte de dados"): um texto que diz qual driver usar (antes dos dois-pontos) e onde está o banco (depois). Aqui: "SQLite, no arquivo
loja.db". - $pdo
- A variável que guarda a conexão. Tudo o que você fizer com o banco passa por ela:
$pdo->query(...),$pdo->exec(...). A seta->quer dizer "use esta função do objeto".
$ php conectar.php
Conectado!
object(PDO)#1 (0) { « um objeto da classe PDO: a conexão
}
$ ls -l loja.db
-rw-r--r-- 1 ana ana 0 out 16 21:02 loja.db « o arquivo foi criado (vazio, por enquanto)
Se o arquivo loja.db não existe, o SQLite o cria na hora, vazio. Isso é prático, mas tem um lado ruim: errar o nome do arquivo não dá erro, só cria outro banco vazio (você vai ver isso em CRUD com PDO).
Os DSNs mais comuns
| DSN | Significa |
|---|---|
sqlite:loja.db | Arquivo loja.db na pasta em que você está ao rodar o programa. |
sqlite:/home/ana/loja/loja.db | Caminho completo: sempre o mesmo arquivo. |
"sqlite:" . __DIR__ . "/loja.db" | O arquivo ao lado do programa, de qualquer pasta que ele seja rodado. A forma recomendada. |
sqlite::memory: | Um banco na memória, que some quando o programa termina. Ótimo para testes e para as caixas do editor. |
mysql:host=localhost;dbname=loja;charset=utf8mb4 | Um servidor MySQL/MariaDB (só para conhecer; veja MySQL e MariaDB). Usuário e senha vão no 2º e 3º argumentos: new PDO($dsn, "ana", "senha"). |
2. Comandos: exec
Para mandar um SQL que faz alguma coisa e não devolve linhas (criar tabela, inserir, alterar, apagar), use exec ("executar"):
<?php
$pdo = new PDO("sqlite:loja.db");
$pdo->exec("CREATE TABLE IF NOT EXISTS produtos (
id INTEGER PRIMARY KEY,
nome TEXT NOT NULL,
preco REAL NOT NULL,
estoque INTEGER NOT NULL
)");
$quantos = $pdo->exec("INSERT INTO produtos (nome, preco, estoque) VALUES
('Caderno', 15.90, 30),
('Caneta azul', 2.50, 100),
('Mochila', 89.90, 5)");
echo "Linhas inseridas: $quantos\n";
$ php montar.php Linhas inseridas: 3 $ ls -l loja.db -rw-r--r-- 1 ana ana 8192 out 16 21:02 loja.db « agora tem tabela e dados
- $pdo->exec("CREATE TABLE …")
- Cria a tabela (o SQL foi explicado em Banco de Dados: o Básico). O texto pode ocupar várias linhas.
- $quantos = $pdo->exec("INSERT …")
- O
execdevolve quantas linhas o comando afetou: aqui, 3 inseridas.
exec e query só com SQL fixo
Nesta aula, todo SQL é escrito por você, sem nada que venha de fora. Quando um valor vier de um formulário ou do usuário (um nome, um id), não cole o valor no texto do SQL: use prepare e execute, que você vai ver em CRUD com PDO. O motivo (SQL injection) é a aula Prepared Statements.
3. Perguntas: query e fetch
Para um SELECT, que devolve linhas, use query ("consulta"). Ele não devolve as linhas direto: devolve um resultado (um objeto PDOStatement), de onde você busca as linhas com fetch ("buscar", "ir pegar").
<?php
$pdo = new PDO("sqlite:loja.db");
$stmt = $pdo->query("SELECT id, nome, preco FROM produtos");
$linha = $stmt->fetch();
print_r($linha);
$ php ler-uma.php
Array
(
[id] => 1
[0] => 1
[nome] => Caderno
[1] => Caderno
[preco] => 15.9
[2] => 15.9
)
- $stmt = $pdo->query(...)
- Manda o
SELECT.$stmt(de statement, "comando") é o resultado, como uma pilha de fichas prontas para pegar. - $stmt->fetch()
- Pega a próxima linha da pilha, como array. Chamando de novo, vem a seguinte. Quando acabam, devolve
false.
Repare que cada valor veio duas vezes: pelo nome da coluna ([nome]) e pela posição ([1]). É o modo padrão, PDO::FETCH_BOTH ("os dois"). Repare também nos tipos: o id veio como número inteiro e o preço como número com casas (15.9, sem o zero do fim; para mostrar 15,90, use number_format).
Escolhendo o formato da linha
Você pode dizer ao fetch como quer cada linha:
<?php
$pdo = new PDO("sqlite:loja.db");
$stmt = $pdo->query("SELECT nome, preco FROM produtos WHERE id = 1");
print_r($stmt->fetch(PDO::FETCH_ASSOC));
$stmt = $pdo->query("SELECT nome, preco FROM produtos WHERE id = 1");
print_r($stmt->fetch(PDO::FETCH_NUM));
$stmt = $pdo->query("SELECT nome, preco FROM produtos WHERE id = 1");
$obj = $stmt->fetch(PDO::FETCH_OBJ);
echo $obj->nome, " custa ", $obj->preco, "\n";
$ php modos.php
Array « FETCH_ASSOC: chaves com os nomes das colunas
(
[nome] => Caderno
[preco] => 15.9
)
Array « FETCH_NUM: chaves 0, 1, 2…
(
[0] => Caderno
[1] => 15.9
)
Caderno custa 15.9 « FETCH_OBJ: um objeto, lido com ->
| Modo | A linha vem como | Você lê com | Quando usar |
|---|---|---|---|
PDO::FETCH_ASSOC | Array associativo | $linha["nome"] | O mais usado; o padrão deste guia |
PDO::FETCH_NUM | Array indexado | $linha[0] | Raramente; com [$nome, $preco] = $linha |
PDO::FETCH_BOTH | Os dois juntos (padrão) | $linha["nome"] ou $linha[1] | Evite: duplica tudo |
PDO::FETCH_OBJ | Objeto simples | $linha->nome | Quem prefere a seta (comum em sistemas prontos) |
Experimente: rode e compare. Depois troque PDO::FETCH_ASSOC por PDO::FETCH_NUM, por PDO::FETCH_BOTH e por PDO::FETCH_OBJ (com o FETCH_OBJ, o print_r mostra stdClass Object).
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE produtos (id INTEGER PRIMARY KEY, nome TEXT, preco REAL)");
$pdo->exec("INSERT INTO produtos (nome, preco) VALUES ('Caderno', 15.90), ('Caneta azul', 2.50)");
$stmt = $pdo->query("SELECT id, nome, preco FROM produtos");
print_r($stmt->fetch(PDO::FETCH_ASSOC));
Todas as linhas: while com fetch
Como o fetch devolve false quando as linhas acabam, ele cabe direitinho num while: "enquanto houver linha, mostre":
<?php
$pdo = new PDO("sqlite:loja.db");
$stmt = $pdo->query("SELECT nome, preco FROM produtos ORDER BY preco");
while ($linha = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $linha["nome"], ": R$ ", number_format($linha["preco"], 2, ",", "."), "\n";
}
$ php listar.php Caneta azul: R$ 2,50 Caderno: R$ 15,90 Mochila: R$ 89,90
A condição $linha = $stmt->fetch(...) faz duas coisas: guarda a linha em $linha e, ao mesmo tempo, serve de teste. Uma linha (array com dados) conta como verdadeiro; false encerra o laço.
Todas de uma vez: fetchAll
Se você quer todas as linhas num array (para contar, ordenar, passar para outra função), use fetchAll:
<?php
$pdo = new PDO("sqlite:loja.db");
$produtos = $pdo->query("SELECT nome, estoque FROM produtos")->fetchAll(PDO::FETCH_ASSOC);
echo "Quantos: ", count($produtos), "\n";
print_r($produtos);
$ php todas.php
Quantos: 3
Array
(
[0] => Array
(
[nome] => Caderno
[estoque] => 30
)
[1] => Array
(
[nome] => Caneta azul
[estoque] => 100
)
[2] => Array
(
[nome] => Mochila
[estoque] => 5
)
)
Um array de arrays: cada posição é uma linha (veja Arrays Multidimensionais). Repare que query(...)->fetchAll(...) está encadeado: o resultado do query já recebe o fetchAll, sem a variável $stmt no meio.
Um valor só: fetchColumn
Para perguntas com uma resposta só (quantos produtos? qual a soma do estoque?), o fetchColumn devolve direto o valor da primeira coluna da primeira linha:
<?php
$pdo = new PDO("sqlite:loja.db");
$total = $pdo->query("SELECT COUNT(*) FROM produtos")->fetchColumn();
$soma = $pdo->query("SELECT SUM(estoque) FROM produtos")->fetchColumn();
echo "Produtos: $total\n";
echo "Itens no estoque: $soma\n";
var_dump($total);
$ php contar.php Produtos: 3 Itens no estoque: 135 « 30 + 100 + 5 int(3)
foreach direto no resultado
O resultado do query também pode ir direto num foreach, que pega uma linha por volta. É a forma mais curta, e você vai vê-la muito:
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE recados (texto TEXT)");
$pdo->exec("INSERT INTO recados VALUES ('Comprar papel'), ('Ligar para o fornecedor')");
foreach ($pdo->query("SELECT texto FROM recados") as $linha) {
echo "- ", $linha["texto"], "\n";
}
$ php memoria.php - Comprar papel - Ligar para o fornecedor
Este exemplo usa sqlite::memory:: o banco nasce, recebe dados e some quando o programa termina. Nenhum arquivo foi criado. É assim que funcionam as caixas "Experimente" desta aula.
| Quero… | Use | Devolve |
|---|---|---|
| Rodar um comando (CREATE, INSERT, UPDATE, DELETE) | $pdo->exec($sql) | Número de linhas afetadas |
| Fazer uma pergunta (SELECT) | $pdo->query($sql) | Um resultado (PDOStatement) |
| A próxima linha | $stmt->fetch() | Array (ou objeto); false no fim |
| Todas as linhas | $stmt->fetchAll() | Array de linhas (vazio se nenhuma) |
| Um valor | $stmt->fetchColumn() | O valor; false se não há linha |
| Percorrer | foreach ($stmt as $linha) | Uma linha por volta |
Missão: o banco tem 3 produtos. Com exec, insira mais um: 'Lápis', preço 1.20. Depois, com SELECT COUNT(*) e fetchColumn(), mostre:
Total: 4 produtos
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE produtos (id INTEGER PRIMARY KEY, nome TEXT, preco REAL)");
$pdo->exec("INSERT INTO produtos (nome, preco) VALUES
('Caderno', 15.90), ('Caneta azul', 2.50), ('Mochila', 89.90)");
// 1. insira o Lápis
// 2. conte os produtos e mostre "Total: N produtos"
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE produtos (id INTEGER PRIMARY KEY, nome TEXT, preco REAL)");
$pdo->exec("INSERT INTO produtos (nome, preco) VALUES
('Caderno', 15.90), ('Caneta azul', 2.50), ('Mochila', 89.90)");
$pdo->exec("INSERT INTO produtos (nome, preco) VALUES ('Lápis', 1.20)");
$total = $pdo->query("SELECT COUNT(*) FROM produtos")->fetchColumn();
echo "Total: $total produtos\n";
4. Erros: PDO::ERRMODE_EXCEPTION
O que acontece quando o SQL está errado? Depende do modo de erro da conexão. Desde o PHP 8.0+, o padrão é PDO::ERRMODE_EXCEPTION: todo erro vira uma exceção (veja Exceções), que para o programa com uma mensagem clara, se não for tratada:
<?php
$pdo = new PDO("sqlite:loja.db");
$stmt = $pdo->query("SELECT nome FROM produto"); // faltou o "s"
$lista = $stmt->fetchAll();
echo "Fim do programa\n";
$ php excecao.php
Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 1 no such table: produto in /home/ana/loja/excecao.php:4
Stack trace:
#0 /home/ana/loja/excecao.php(4): PDO->query('SELECT nome FRO...')
#1 {main}
thrown in /home/ana/loja/excecao.php on line 4
A mensagem diz o quê (no such table: produto, "não existe a tabela produto") e onde (linha 4, no query). Agora o mesmo programa no modo antigo, PDO::ERRMODE_SILENT ("silencioso"), que era o padrão até o PHP 7:
<?php
$pdo = new PDO("sqlite:loja.db");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$stmt = $pdo->query("SELECT nome FROM produto"); // faltou o "s"
var_dump($stmt);
print_r($pdo->errorInfo());
$lista = $stmt->fetchAll();
echo "Fim do programa\n";
$ php silencioso.php
bool(false) « o query falhou calado e devolveu false
Array
(
[0] => HY000
[1] => 1
[2] => no such table: produto « o motivo só aparece se você perguntar
)
Fatal error: Uncaught Error: Call to a member function fetchAll() on false in /home/ana/loja/silencioso.php:9
Stack trace:
#0 {main}
thrown in /home/ana/loja/silencioso.php on line 9
No modo silencioso, o query não reclama: só devolve false. O motivo fica guardado em errorInfo(), e o programa só quebra depois, na linha 9, com um erro que não fala nada de banco (Call to a member function fetchAll() on false, "chamar a função fetchAll em false"). Imagine procurar o problema na linha 9 quando ele está na linha 5. Por isso: deixe sempre no modo exceção.
Opções na conexão
Mesmo sendo o padrão, é costume escrever o modo de erro na conexão (deixa claro, e protege se o código rodar num PHP antigo). Junto, vale definir o formato padrão das linhas, para não repetir PDO::FETCH_ASSOC em todo fetch. As opções vão num array, no 4º argumento:
<?php
$pdo = new PDO("sqlite:loja.db", null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
foreach ($pdo->query("SELECT nome, estoque FROM produtos") as $linha) {
echo $linha["nome"], " (", $linha["estoque"], ")\n";
}
$ php opcoes.php Caderno (30) Caneta azul (100) Mochila (5)
- null, null
- O 2º e o 3º argumentos são usuário e senha. O SQLite não usa, então vão vazios (
null). - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
- "Atributo modo de erro: exceção."
- PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
- "Formato padrão das linhas: associativo." Agora
fetch(),fetchAll()e oforeachjá entregam$linha["nome"].
Com argumentos nomeados (PHP 8.0+) dá para pular os dois null: new PDO("sqlite:loja.db", options: [...]). É a forma usada em CRUD com PDO. Depois de conectado, também dá para mudar uma opção com $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) e consultar com getAttribute:
<?php
$pdo = new PDO("sqlite:loja.db");
echo "Driver: ", $pdo->getAttribute(PDO::ATTR_DRIVER_NAME), "\n";
echo "Versão do SQLite: ", $pdo->getAttribute(PDO::ATTR_SERVER_VERSION), "\n";
echo "Modo de erro: ", $pdo->getAttribute(PDO::ATTR_ERRMODE), " (", PDO::ERRMODE_EXCEPTION, " = exceção)\n";
$ php atributos.php Driver: sqlite Versão do SQLite: 3.45.2 Modo de erro: 2 (2 = exceção) « o padrão do PHP 8
O erro de conexão
A conexão também pode falhar: o arquivo está numa pasta que não existe, sem permissão, ou (no MySQL) o servidor está desligado. O new PDO lança uma PDOException, e você decide o que mostrar com try/catch:
<?php
try {
$pdo = new PDO("sqlite:/dados/loja.db");
echo "Conectado!\n";
} catch (PDOException $e) {
echo "Não consegui abrir o banco.\n";
echo "Detalhe: ", $e->getMessage(), "\n";
echo "Código: ", $e->getCode(), "\n";
}
$ php tratar.php Não consegui abrir o banco. Detalhe: SQLSTATE[HY000] [14] unable to open database file Código: 14
- try { … }
- "Tente": o código que pode falhar.
- catch (PDOException $e)
- "Se der erro de PDO, pegue-o em
$e." - $e->getMessage()
- A mensagem:
unable to open database file("não consegui abrir o arquivo do banco"). A pasta/dadosnão existe, e o SQLite não cria pastas, só o arquivo. - $e->getCode()
- O código do erro (14, no SQLite, é "não consegui abrir").
Num site, não mostre o getMessage() ao visitante: ele pode revelar caminhos de pastas e nomes de servidores. Mostre "O sistema está fora do ar, tente mais tarde" e grave o detalhe num log com error_log($e->getMessage()) (veja Depurar). A aula MySQL e MariaDB mostra isso com as mensagens reais de um servidor que não responde.
Fechar a conexão
A conexão fecha sozinha quando o programa termina (no fim de cada página, num site). Se precisar fechar antes, apague a variável: $pdo = null;.
Quando dá errado
unable to open database file
<?php
$pdo = new PDO("sqlite:/dados/loja.db");
$ php sem-pasta.php
Fatal error: Uncaught PDOException: SQLSTATE[HY000] [14] unable to open database file in /home/ana/loja/sem-pasta.php:2
Stack trace:
#0 /home/ana/loja/sem-pasta.php(2): PDO->__construct('sqlite:/dados/l...')
#1 {main}
thrown in /home/ana/loja/sem-pasta.php on line 2
O que significa: o SQLite não conseguiu abrir nem criar o arquivo. Causas: a pasta não existe (aqui, /dados), ou o PHP não tem permissão de escrever nela (comum num servidor web, que roda com outro usuário).
Como consertar: confira o caminho; crie a pasta (mkdir); confira as permissões da pasta e do arquivo. Prefira __DIR__ . "/loja.db".
could not find driver
<?php
$pdo = new PDO("sqlite3:loja.db");
$ php driver-errado.php
Fatal error: Uncaught PDOException: could not find driver in /home/ana/loja/driver-errado.php:2
Stack trace:
#0 /home/ana/loja/driver-errado.php(2): PDO->__construct('sqlite3:loja.db')
#1 {main}
thrown in /home/ana/loja/driver-errado.php on line 2
O que significa: "não encontrei o driver" sqlite3. O prefixo do DSN para SQLite é sqlite:, sem o 3. A mesma mensagem aparece quando o nome está certo mas a extensão não está instalada (como mysql: sem o pdo_mysql).
Como consertar: confira o prefixo e rode php -r 'print_r(PDO::getAvailableDrivers());'.
must be a valid data source name
<?php
$pdo = new PDO("loja.db");
$ php dsn-errado.php
Fatal error: Uncaught PDOException: PDO::__construct(): Argument #1 ($dsn) must be a valid data source name in /home/ana/loja/dsn-errado.php:2
Stack trace:
#0 /home/ana/loja/dsn-errado.php(2): PDO->__construct('loja.db')
#1 {main}
thrown in /home/ana/loja/dsn-errado.php on line 2
O que significa: "o argumento nº 1 ($dsn) precisa ser um nome de fonte de dados válido". Faltou o driver e os dois-pontos: o PDO recebeu só o nome do arquivo.
Como consertar: new PDO("sqlite:loja.db").
near "SELEC": syntax error
<?php
$pdo = new PDO("sqlite:loja.db");
$stmt = $pdo->query("SELEC nome FROM produtos");
$ php sintaxe.php
Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 1 near "SELEC": syntax error in /home/ana/loja/sintaxe.php:4
Stack trace:
#0 /home/ana/loja/sintaxe.php(4): PDO->query('SELEC nome FROM...')
#1 {main}
thrown in /home/ana/loja/sintaxe.php on line 4
O que significa: o PHP está certo; o SQL dentro do texto está errado. O SQLite mostra onde se perdeu: near "SELEC" ("perto de SELEC"). Erros de SQL só aparecem quando o programa roda, porque, para o PHP, o SQL é só um texto.
Como consertar: leia a palavra depois de near e a anterior: o erro está ali. Na dúvida, teste o SQL sozinho, com echo antes do query.
Call to a member function fetchAll() on false
Aparece no modo silencioso (veja silencioso.php, acima): o query falhou, devolveu false, e o programa tentou usar o resultado.
Como consertar: não use ERRMODE_SILENT. Com ERRMODE_EXCEPTION, o erro aparece na linha certa e com o motivo real.
Undefined array key "nome"
<?php
$pdo = new PDO("sqlite:loja.db");
$stmt = $pdo->query("SELECT nome, preco FROM produtos WHERE id = 1");
$linha = $stmt->fetch(PDO::FETCH_NUM);
echo $linha["nome"], "\n";
$ php modo-errado.php Warning: Undefined array key "nome" in /home/ana/loja/modo-errado.php on line 7
O que significa: "chave de array indefinida: nome". Com FETCH_NUM, a linha tem as chaves 0 e 1, não "nome". O mesmo aviso aparece se o nome da chave não bate com o da coluna ($linha["Nome"], ou uma coluna que não está no SELECT).
Como consertar: use FETCH_ASSOC (ou defina-o como padrão na conexão) e escreva as chaves exatamente como as colunas do SELECT. Na dúvida, print_r($linha).
Missão: este programa deveria listar os produtos do mais barato para o mais caro, mas enche a tela de avisos. Rode, leia o primeiro aviso e corrija (é uma palavra só). A saída correta é:
Caneta azul: R$ 2,50 Caderno: R$ 15,90 Mochila: R$ 89,90
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE produtos (id INTEGER PRIMARY KEY, nome TEXT, preco REAL)");
$pdo->exec("INSERT INTO produtos (nome, preco) VALUES
('Caderno', 15.90), ('Caneta azul', 2.50), ('Mochila', 89.90)");
$stmt = $pdo->query("SELECT nome, preco FROM produtos ORDER BY preco");
while ($linha = $stmt->fetch(PDO::FETCH_NUM)) {
echo $linha["nome"], ": R$ ", number_format($linha["preco"], 2, ",", "."), "\n";
}
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE produtos (id INTEGER PRIMARY KEY, nome TEXT, preco REAL)");
$pdo->exec("INSERT INTO produtos (nome, preco) VALUES
('Caderno', 15.90), ('Caneta azul', 2.50), ('Mochila', 89.90)");
$stmt = $pdo->query("SELECT nome, preco FROM produtos ORDER BY preco");
while ($linha = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $linha["nome"], ": R$ ", number_format($linha["preco"], 2, ",", "."), "\n";
}
Referência
| Código | O que faz |
|---|---|
new PDO($dsn) | Conecta (SQLite) |
new PDO($dsn, $usuario, $senha, $opcoes) | Conecta com usuário, senha e opções (MySQL e outros) |
PDO::getAvailableDrivers() | Lista os drivers deste PHP |
$pdo->exec($sql) | Roda um comando; devolve as linhas afetadas |
$pdo->query($sql) | Roda um SELECT; devolve um PDOStatement |
$stmt->fetch($modo) | Próxima linha, ou false |
$stmt->fetchAll($modo) | Todas as linhas num array |
$stmt->fetchColumn() | Valor da 1ª coluna da próxima linha |
PDO::FETCH_ASSOC / FETCH_NUM / FETCH_BOTH / FETCH_OBJ | Formato da linha |
PDO::ATTR_ERRMODE | Modo de erro: ERRMODE_EXCEPTION (padrão no PHP 8), ERRMODE_WARNING, ERRMODE_SILENT |
PDO::ATTR_DEFAULT_FETCH_MODE | Formato padrão das linhas |
$pdo->setAttribute($attr, $valor) / getAttribute($attr) | Muda / consulta uma opção |
$pdo->errorInfo() | Detalhes do último erro (útil no modo silencioso) |
$e->getMessage(), $e->getCode() | Mensagem e código de uma PDOException |
$pdo = null | Fecha a conexão antes do fim do programa |
Exercícios
1. O DSN
Complete para abrir o arquivo escola.db com SQLite:
2. Banco temporário
Complete o DSN para criar um banco SQLite que só existe na memória:
3. Linhas com nome
Complete para cada linha vir como array associativo:
4. Qual método usar para CREATE TABLE e INSERT com SQL fixo?
5. O que $stmt->fetch() devolve quando não há mais linhas?
6. Por que preferir PDO::ERRMODE_EXCEPTION a PDO::ERRMODE_SILENT?
7. $pdo->query("SELECT COUNT(*) FROM produtos")->fetchColumn() devolve…
Resumo
- O PDO é a forma única de o PHP falar com bancos; o driver (
pdo_sqlite,pdo_mysql…) sabe falar com cada um. - Conecte com
new PDO("sqlite:loja.db"). O DSN diz o driver e onde está o banco;sqlite::memory:é um banco temporário. execpara comandos (devolve linhas afetadas);queryparaSELECT(devolve um resultado).- Leia o resultado com
fetch(uma linha,falseno fim),fetchAll(todas),fetchColumn(um valor) ouforeach. - Use
PDO::FETCH_ASSOC, de preferência como padrão:PDO::ATTR_DEFAULT_FETCH_MODE. - Deixe
PDO::ERRMODE_EXCEPTION(o padrão do PHP 8) e trate o erro de conexão comtry/catch. - Valores que vêm de fora nunca vão colados no SQL: isso é
prepare/execute, na próxima aula.
Próxima aula: CRUD com PDO, para cadastrar, listar, atualizar e apagar os produtos da lojinha.