Introdução ao PDO: Por que usar?
PDO (PHP Data Objects) é uma abstração de banco de dados que oferece uma interface consistente para trabalhar com múltiplos sistemas de gerenciamento de dados. Diferentemente da extensão MySQLi, o PDO permite que você mude de banco de dados (MySQL, PostgreSQL, SQLite) sem reescrever todo o código. É seguro por padrão contra injeção SQL quando usado corretamente com prepared statements, e oferece tratamento robusto de erros.
Neste artigo, você aprenderá a conectar-se a um banco MySQL, executar queries seguras e gerenciar transações. Vamos focar em boas práticas profissionais que você usará em produção.
Conectando ao MySQL com PDO
Estabelecendo a Conexão
A conexão é o primeiro passo. O PDO usa a sintaxe de Data Source Name (DSN) para identificar o banco:
<?php
$host = 'localhost';
$db = 'meu_banco';
$user = 'root';
$pass = 'senha123';
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
try {
$pdo = new PDO($dsn, $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Conectado com sucesso!";
} catch (PDOException $e) {
die('Erro na conexão: ' . $e->getMessage());
}
?>
O atributo ATTR_ERRMODE é crítico: PDO::ERRMODE_EXCEPTION lança exceções em erros, permitindo tratamento profissional. A linha do charset garante compatibilidade com caracteres especiais em UTF-8.
Armazenando em Arquivo de Configuração
Em produção, nunca coloque credenciais no código. Crie um arquivo separado:
// config/database.php
<?php
return [
'host' => getenv('DB_HOST') ?: 'localhost',
'db' => getenv('DB_NAME') ?: 'meu_banco',
'user' => getenv('DB_USER') ?: 'root',
'pass' => getenv('DB_PASS') ?: '',
];
E use assim:
// index.php
<?php
$config = require 'config/database.php';
$dsn = "mysql:host={$config['host']};dbname={$config['db']};charset=utf8mb4";
try {
$pdo = new PDO($dsn, $config['user'], $config['pass']);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die('Erro: ' . $e->getMessage());
}
?>
Executando Queries de Forma Segura
Prepared Statements: Sua Defesa Contra Injeção SQL
Prepared statements separam a estrutura SQL dos dados, eliminando a vulnerabilidade de injeção:
<?php
// ✗ ERRADO - Vulnerável
$email = $_POST['email'];
$result = $pdo->query("SELECT * FROM usuarios WHERE email = '$email'");
// ✓ CORRETO - Seguro
$email = $_POST['email'];
$stmt = $pdo->prepare("SELECT * FROM usuarios WHERE email = ?");
$stmt->execute([$email]);
$usuario = $stmt->fetch(PDO::FETCH_ASSOC);
if ($usuario) {
echo "Bem-vindo, " . htmlspecialchars($usuario['nome']);
}
?>
Existem duas sintaxes: placeholders posicionais (?) ou nomeados (:email). A versão nomeada é mais legível em queries complexas:
<?php
$stmt = $pdo->prepare("SELECT * FROM usuarios WHERE email = :email AND status = :status");
$stmt->execute([
':email' => $_POST['email'],
':status' => 'ativo'
]);
$usuario = $stmt->fetch(PDO::FETCH_ASSOC);
?>
INSERT, UPDATE e DELETE
Para operações de modificação, use o mesmo padrão:
<?php
// INSERT
$stmt = $pdo->prepare("INSERT INTO usuarios (nome, email, senha) VALUES (?, ?, ?)");
$stmt->execute([
'João Silva',
'joao@example.com',
password_hash('senha123', PASSWORD_BCRYPT)
]);
$novoId = $pdo->lastInsertId();
echo "Usuário criado com ID: $novoId";
// UPDATE
$stmt = $pdo->prepare("UPDATE usuarios SET nome = ?, email = ? WHERE id = ?");
$stmt->execute(['João Santos', 'joao.santos@example.com', 5]);
echo "Linhas afetadas: " . $stmt->rowCount();
// DELETE
$stmt = $pdo->prepare("DELETE FROM usuarios WHERE id = ?");
$stmt->execute([5]);
echo "Linhas deletadas: " . $stmt->rowCount();
?>
Trabalhando com Resultados e Transações
Recuperando Dados com Diferentes Formatos
O PDO oferece várias formas de buscar dados:
<?php
$stmt = $pdo->prepare("SELECT id, nome, email FROM usuarios WHERE id > ?");
$stmt->execute([10]);
// Um registro como array associativo
$usuario = $stmt->fetch(PDO::FETCH_ASSOC);
echo $usuario['nome'];
// Um registro como objeto
$usuario = $stmt->fetch(PDO::FETCH_OBJ);
echo $usuario->email;
// Todos os registros como array
$stmt->execute([10]);
$usuarios = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($usuarios as $user) {
echo $user['nome'] . "\n";
}
// Contando resultados
$stmt->execute([10]);
$total = $stmt->rowCount();
echo "Total de usuários: $total";
?>
Transações: Garantindo Integridade
Transações garantem que múltiplas operações sejam executadas como um bloco atômico:
<?php
try {
$pdo->beginTransaction();
// Deduz saldo da conta origem
$stmt = $pdo->prepare("UPDATE contas SET saldo = saldo - ? WHERE id = ?");
$stmt->execute([100, 1]);
// Adiciona saldo na conta destino
$stmt = $pdo->prepare("UPDATE contas SET saldo = saldo + ? WHERE id = ?");
$stmt->execute([100, 2]);
// Registra a transferência
$stmt = $pdo->prepare("INSERT INTO transferencias (origem, destino, valor) VALUES (?, ?, ?)");
$stmt->execute([1, 2, 100]);
$pdo->commit();
echo "Transferência realizada com sucesso!";
} catch (PDOException $e) {
$pdo->rollBack();
die("Erro na transferência: " . $e->getMessage());
}
?>
Se qualquer operação falhar, o rollBack() desfaz tudo. Sem transações, você poderia perder dinheiro.
Conclusão
Você aprendeu três pilares para trabalhar profissionalmente com MySQL em PHP: (1) conectar-se de forma segura usando PDO com tratamento de exceções e armazenamento correto de credenciais; (2) executar queries seguras contra injeção SQL através de prepared statements com placeholders; (3) recuperar dados em múltiplos formatos e manter integridade com transações.
Coloque isso em prática agora. Crie um pequeno projeto que insira e recupere dados, teste o tratamento de erros e valide suas queries contra injeção. Essa é a base sólida que diferencia profissionais de iniciantes.