Operações com bancos de dados PDO
Você já aprendeu os comandos do MySQL, mas o verdadeiro objetivo é operar o banco de dados a partir do PHP. O PDO (PHP Data Objects) é a camada de abstração de banco de dados padrão recomendada pelo PHP — um único conjunto de código funciona com 12 tipos de bancos de dados. Lembre-se: aprenda PDO, ignore o MySQLi.
1. Por que o PDO?
| PDO | MySQLi | |
|---|---|---|
| Bancos de dados compatíveis | 12 (MySQL/PostgreSQL/SQLite...) | Apenas MySQL |
| Parâmetros nomeados | ✅ :name |
❌ apenas ? |
| Recuperar matrizes associativas | ✅ PDO::FETCH_ASSOC |
✅ |
| Buscar objetos | ✅ PDO::FETCH_OBJ |
❌ (requer configuração adicional) |
| Modo de exceção | ✅ Configurável | ✅ Configurável |
| Modernidade | 🏆 Padrão da comunidade | Tradição |
2. Conexão PDO
<?php
$host = 'localhost';
$dbname = 'myblog';
$username = 'root';
$password = '';
$charset = 'utf8mb4';
$dsn = "mysql:host={$host};dbname={$dbname};charset={$charset}";
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
echo "✅ Database connected successfully!<br>";
} catch (PDOException $e) {
die("❌ Connection failed: " . $e->getMessage());
}
?>
| Opção de conexão | Significado | Por que |
|---|---|---|
ERRMODE_EXCEPTION |
Lançar exceções em caso de erros | Sem falhas silenciosas |
FETCH_ASSOC |
Padrão para matrizes associativas | Formato mais utilizado |
EMULATE_PREPARES => false |
Use instruções preparadas de verdade | Segurança de verdade |
EMULATE_PREPARES => false garante que sejam utilizadas as instruções preparadas nativas do MySQL, em vez das emuladas pelo PDO.
3. query() — Execução de consultas SELECT
<?php
// Simple query
$stmt = $pdo->query("SELECT * FROM users");
$users = $stmt->fetchAll();
// Iterate results
foreach ($users as $user) {
echo "ID: {$user['id']}, Username: {$user['username']}<br>";
}
// Fetch a single row
$stmt = $pdo->query("SELECT * FROM users WHERE id = 1");
$user = $stmt->fetch();
echo $user['username']; // John
?>
(1) Modos de busca
<?php
$stmt = $pdo->query("SELECT id, username FROM users");
// Associative array (default)
$row = $stmt->fetch(PDO::FETCH_ASSOC);
echo $row['username'];
// Numeric index
$row = $stmt->fetch(PDO::FETCH_NUM);
echo $row[1];
// Object
$row = $stmt->fetch(PDO::FETCH_OBJ);
echo $row->username;
// Fetch a single column
$usernames = $stmt->fetchAll(PDO::FETCH_COLUMN, 1);
print_r($usernames); // ['John', 'Jane', ...]
?>
4. Instruções preparadas (Fundamental!)
As instruções preparadas são a chave para prevenir a injeção de SQL:
▶ Exemplo: Consulta segura do usuário
<?php
// ❌ Dangerous: direct SQL concatenation (SQL injection vulnerability)
// $stmt = $pdo->query("SELECT * FROM users WHERE username = '$input'");
// ✅ Safe: prepared statement
$username = $_GET['username'] ?? '';
$sql = "SELECT * FROM users WHERE username = :username";
$stmt = $pdo->prepare($sql);
$stmt->execute(['username' => $username]);
$user = $stmt->fetch();
if ($user) {
echo "Found user: {$user['username']}";
} else {
echo "User not found";
}
?>
(1) INSERIR
<?php
$sql = "INSERT INTO users (username, email, password, age)
VALUES (:username, :email, :password, :age)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'username' => 'Alex',
'email' => 'alex@example.com',
'password' => password_hash('123456', PASSWORD_DEFAULT),
'age' => 24,
]);
$newId = $pdo->lastInsertId();
echo "New user ID: {$newId}";
?>
(2) ATUALIZAÇÃO
<?php
$sql = "UPDATE users SET age = :age WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['age' => 27, 'id' => 1]);
echo "Affected {$stmt->rowCount()} row(s)";
?>
(3) EXCLUIR
<?php
$sql = "DELETE FROM users WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute(['id' => 5]);
echo "Deleted {$stmt->rowCount()} row(s)";
?>
5. CRUD completo na prática
▶ Exemplo: Página de gerenciamento de usuários
<?php
// Database connection (same as above, omitted for brevity)
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'add') {
$stmt = $pdo->prepare(
"INSERT INTO users (username, email, password, age)
VALUES (:username, :email, :password, :age)"
);
$stmt->execute([
'username' => $_POST['username'],
'email' => $_POST['email'],
'password' => password_hash($_POST['password'], PASSWORD_DEFAULT),
'age' => (int)$_POST['age'],
]);
echo "<p style='color:green'>User added successfully!</p>";
} elseif ($action === 'delete') {
$stmt = $pdo->prepare("DELETE FROM users WHERE id = :id");
$stmt->execute(['id' => (int)$_POST['id']]);
echo "<p style='color:green'>User deleted!</p>";
}
}
// Query all users
$users = $pdo->query("SELECT * FROM users ORDER BY id DESC")->fetchAll();
?>
<h2>User Management</h2>
<table border="1" cellpadding="8">
<tr><th>ID</th><th>Username</th><th>Email</th><th>Age</th><th>Registered</th><th>Actions</th></tr>
<?php foreach ($users as $u): ?>
<tr>
<td><?= $u['id'] ?></td>
<td><?= htmlspecialchars($u['username']) ?></td>
<td><?= htmlspecialchars($u['email']) ?></td>
<td><?= $u['age'] ?></td>
<td><?= $u['created_at'] ?></td>
<td>
<form method="POST" style="display:inline">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= $u['id'] ?>">
<button type="submit" onclick="return confirm('Confirm deletion?')">Delete</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</table>
<h3>Add User</h3>
<form method="POST">
<input type="hidden" name="action" value="add">
<input type="text" name="username" placeholder="Username" required>
<input type="email" name="email" placeholder="Email" required>
<input type="password" name="password" placeholder="Password" required>
<input type="number" name="age" placeholder="Age">
<button type="submit">Add</button>
</form>
❓ Perguntas Frequentes
P: PDO ou MySQLi — qual devo escolher? R: PDO. Ele oferece suporte a 12 tipos de bancos de dados (é possível alternar entre bancos de dados sem precisar reescrever o código), possui uma sintaxe mais clara para instruções preparadas (
:nameparâmetros nomeados) e é o padrão aceito pela comunidade PHP. O MySQLi é adequado apenas para a manutenção de projetos legados.
P: Por que as instruções preparadas evitam a injeção de SQL? R: As instruções preparadas separam a estrutura do SQL dos dados — o SQL é enviado ao MySQL e compilado em um plano de execução primeiro, e os dados são passados como parâmetros posteriormente. O banco de dados sabe exatamente o que é um comando e o que são dados, por isso nunca trata os dados como código executável.
P: Qual é a diferença entre
fetch()efetchAll()? R:fetch()recupera uma linha por vez (cada chamada retorna uma linha) — ideal para conjuntos de resultados grandes.fetchAll()recupera tudo de uma só vez em um array — mais simples, mas pode consumir muita memória em conjuntos de dados grandes.
📖 Resumo
- O PDO é a camada de abstração de banco de dados oficialmente recomendada pelo PHP, com suporte a 12 tipos de bancos de dados
- As três opções padrão de conexão: ERRMODE_EXCEPTION / FETCH_ASSOC / EMULATE_PREPARES=false
query()executa a instrução SELECT,fetchAll()recupera todos os resultados,fetch()recupera um- As instruções preparadas (prepare/execute) evitam a injeção de SQL
- Os placeholders nomeados
:namesão mais claros do que? lastInsertId()retorna o último ID inserido;rowCount()retorna o número de linhas afetadas
📝 Exercícios
- Use o PDO para se conectar ao banco de dados do myblog, consultar todos os dados da tabela users e exibi-los em uma tabela.
- Crie uma página de cadastro com um formulário para nome de usuário/e-mail/senha. Use instruções preparadas do PDO para inserir o novo usuário (não se esqueça de
password_hash). - Adicione um botão “Excluir” a cada linha da tabela do exercício 1. Ao clicar nele, o registro do usuário correspondente deve ser excluído.



