<h2>Introdução ao PDO: Por que usar?</h2>
<p>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.</p>
<p>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.</p>
<h2>Conectando ao MySQL com PDO</h2>
<h3>Estabelecendo a Conexão</h3>
<p>A conexão é o primeiro passo. O PDO usa a sintaxe de Data Source Name (DSN) para identificar o banco:</p>
<pre><code class="language-php"><?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());
}
?></code></pre>
<p>O atributo <code>ATTR_ERRMODE</code> é crítico: <code>PDO::ERRMODE_EXCEPTION</code> lança exceções em erros, permitindo tratamento profissional. A linha do charset garante compatibilidade com caracteres especiais em UTF-8.</p>
<h3>Armazenando em Arquivo de Configuração</h3>
<p>Em produção, nunca coloque credenciais no código. Crie um arquivo separado:</p>
<pre><code class="language-php">// 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') ?: '',
];</code></pre>
<p>E use assim:</p>
<pre><code class="language-php">// 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());
}
?></code></pre>
<h2>Executando Queries de Forma Segura</h2>
<h3>Prepared Statements: Sua Defesa Contra Injeção SQL</h3>
<p>Prepared statements separam a estrutura SQL dos dados, eliminando a vulnerabilidade de injeção:</p>
<pre><code class="language-php"><?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']);
}
?></code></pre>
<p>Existem duas sintaxes: placeholders posicionais (<code>?</code>) ou nomeados (<code>:email</code>). A versão nomeada é mais legível em queries complexas:</p>
<pre><code class="language-php"><?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);
?></code></pre>
<h3>INSERT, UPDATE e DELETE</h3>
<p>Para operações de modificação, use o mesmo padrão:</p>
<pre><code class="language-php"><?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();
?></code></pre>
<h2>Trabalhando com Resultados e Transações</h2>
<h3>Recuperando Dados com Diferentes Formatos</h3>
<p>O PDO oferece várias formas de buscar dados:</p>
<pre><code class="language-php"><?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";
?></code></pre>
<h3>Transações: Garantindo Integridade</h3>
<p>Transações garantem que múltiplas operações sejam executadas como um bloco atômico:</p>
<pre><code class="language-php"><?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());
}
?></code></pre>
<p>Se qualquer operação falhar, o <code>rollBack()</code> desfaz tudo. Sem transações, você poderia perder dinheiro.</p>
<h2>Conclusão</h2>
<p>Você aprendeu três pilares para trabalhar profissionalmente com MySQL em PHP: <strong>(1)</strong> conectar-se de forma segura usando PDO com tratamento de exceções e armazenamento correto de credenciais; <strong>(2)</strong> executar queries seguras contra injeção SQL através de prepared statements com placeholders; <strong>(3)</strong> recuperar dados em múltiplos formatos e manter integridade com transações.</p>
<p>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.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.php.net/manual/pt_BR/book.pdo.php" target="_blank" rel="noopener noreferrer">Documentação Oficial PDO - PHP.net</a></li>
<li><a href="https://www.php.net/manual/pt_BR/pdo.prepared-statements.php" target="_blank" rel="noopener noreferrer">PDO Prepared Statements</a></li>
<li><a href="https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html" target="_blank" rel="noopener noreferrer">OWASP SQL Injection Prevention</a></li>
<li><a href="https://phptherightway.com/#databases" target="_blank" rel="noopener noreferrer">PHP: The Right Way - Database</a></li>
<li><a href="https://www.sitepoint.com/imperative-vs-declarative-programming-php/" target="_blank" rel="noopener noreferrer">Real PHP Security: PDO and Password Hashing</a></li>
</ul>