PHP

CRUD Completo com PDO: Create, Read, Update, Delete: Do Básico ao Avançado

7 min de leitura

CRUD Completo com PDO: Create, Read, Update, Delete: Do Básico ao Avançado

Preparando o Ambiente: Conexão com PDO A PDO (PHP Data Objects) é uma camada de abstração que permite trabalhar com múltiplos bancos de dados usando uma interface uniforme. Antes de implementar o CRUD, você precisa estabelecer uma conexão segura e reutilizável. Crie um arquivo para centralizar a conexão: O atributo garante que erros sejam lançados como exceções, facilitando o tratamento. Guarde credenciais sensíveis em variáveis de ambiente em produção. CREATE: Inserindo Dados no Banco A operação CREATE adiciona novos registros ao banco. Use prepared statements sempre para evitar SQL Injection. Parâmetros nomeados ( ) são mais legíveis que placeholders ( ). O retorna verdadeiro se bem-sucedido. Use se precisar do ID gerado automaticamente. READ: Recuperando e Exibindo Dados Read é a operação mais frequente. Implemente métodos para recuperar um registro específico, todos os registros ou aplicar filtros e paginação. retorna todos os resultados como array; retorna apenas um. retorna associativo (chaves nomeadas); use para objetos. UPDATE: Modificando Registros Existentes Update

<h2>Preparando o Ambiente: Conexão com PDO</h2>

<p>A PDO (PHP Data Objects) é uma camada de abstração que permite trabalhar com múltiplos bancos de dados usando uma interface uniforme. Antes de implementar o CRUD, você precisa estabelecer uma conexão segura e reutilizável.</p>

<p>Crie um arquivo <code>Database.php</code> para centralizar a conexão:</p>

<pre><code class="language-php">&lt;?php

class Database {

private $host = &#039;localhost&#039;;

private $db = &#039;loja&#039;;

private $user = &#039;root&#039;;

private $pass = &#039;&#039;;

private $pdo;

public function connect() {

try {

$this-&gt;pdo = new PDO(

&#039;mysql:host=&#039; . $this-&gt;host . &#039;;dbname=&#039; . $this-&gt;db,

$this-&gt;user,

$this-&gt;pass,

[PDO::ATTR_ERRMODE =&gt; PDO::ERRMODE_EXCEPTION]

);

return $this-&gt;pdo;

} catch (PDOException $e) {

die(&#039;Erro na conexão: &#039; . $e-&gt;getMessage());

}

}

}

?&gt;</code></pre>

<p>O atributo <code>ERRMODE_EXCEPTION</code> garante que erros sejam lançados como exceções, facilitando o tratamento. Guarde credenciais sensíveis em variáveis de ambiente em produção.</p>

<h2>CREATE: Inserindo Dados no Banco</h2>

<p>A operação CREATE adiciona novos registros ao banco. Use <strong>prepared statements</strong> sempre para evitar SQL Injection. Parâmetros nomeados (<code>:nome</code>) são mais legíveis que placeholders (<code>?</code>).</p>

<pre><code class="language-php">&lt;?php

class Produto {

private $pdo;

public function __construct(PDO $pdo) {

$this-&gt;pdo = $pdo;

}

public function criar($nome, $preco, $estoque) {

$sql = &quot;INSERT INTO produtos (nome, preco, estoque, criado_em)

VALUES (:nome, :preco, :estoque, NOW())&quot;;

$stmt = $this-&gt;pdo-&gt;prepare($sql);

return $stmt-&gt;execute([

&#039;:nome&#039; =&gt; $nome,

&#039;:preco&#039; =&gt; $preco,

&#039;:estoque&#039; =&gt; $estoque

]);

}

}

// Uso:

$db = new Database();

$pdo = $db-&gt;connect();

$produto = new Produto($pdo);

if ($produto-&gt;criar(&#039;Notebook&#039;, 2500.00, 10)) {

echo &quot;Produto inserido com sucesso!&quot;;

}

?&gt;</code></pre>

<p>O <code>execute()</code> retorna verdadeiro se bem-sucedido. Use <code>$this-&gt;pdo-&gt;lastInsertId()</code> se precisar do ID gerado automaticamente.</p>

<h2>READ: Recuperando e Exibindo Dados</h2>

<p>Read é a operação mais frequente. Implemente métodos para recuperar um registro específico, todos os registros ou aplicar filtros e paginação.</p>

<pre><code class="language-php">&lt;?php

public function obterTodos($limit = 10, $offset = 0) {

$sql = &quot;SELECT * FROM produtos LIMIT :limit OFFSET :offset&quot;;

$stmt = $this-&gt;pdo-&gt;prepare($sql);

$stmt-&gt;bindValue(&#039;:limit&#039;, (int)$limit, PDO::PARAM_INT);

$stmt-&gt;bindValue(&#039;:offset&#039;, (int)$offset, PDO::PARAM_INT);

$stmt-&gt;execute();

return $stmt-&gt;fetchAll(PDO::FETCH_ASSOC);

}

public function obterPorId($id) {

$sql = &quot;SELECT * FROM produtos WHERE id = :id&quot;;

$stmt = $this-&gt;pdo-&gt;prepare($sql);

$stmt-&gt;execute([&#039;:id&#039; =&gt; $id]);

return $stmt-&gt;fetch(PDO::FETCH_ASSOC);

}

public function buscar($termo) {

$sql = &quot;SELECT * FROM produtos WHERE nome LIKE :termo&quot;;

$stmt = $this-&gt;pdo-&gt;prepare($sql);

$stmt-&gt;execute([&#039;:termo&#039; =&gt; &quot;%{$termo}%&quot;]);

return $stmt-&gt;fetchAll(PDO::FETCH_ASSOC);

}

?&gt;</code></pre>

<p><strong><code>fetchAll()</code></strong> retorna todos os resultados como array; <strong><code>fetch()</code></strong> retorna apenas um. <code>PDO::FETCH_ASSOC</code> retorna associativo (chaves nomeadas); use <code>PDO::FETCH_OBJ</code> para objetos.</p>

<h2>UPDATE: Modificando Registros Existentes</h2>

<p>Update altera dados já presentes no banco. Sempre valide e verifique se o registro existe antes de atualizar para evitar operações silenciosas.</p>

<pre><code class="language-php">&lt;?php

public function atualizar($id, $nome, $preco, $estoque) {

$sql = &quot;UPDATE produtos

SET nome = :nome, preco = :preco, estoque = :estoque, atualizado_em = NOW()

WHERE id = :id&quot;;

$stmt = $this-&gt;pdo-&gt;prepare($sql);

$resultado = $stmt-&gt;execute([

&#039;:id&#039; =&gt; $id,

&#039;:nome&#039; =&gt; $nome,

&#039;:preco&#039; =&gt; $preco,

&#039;:estoque&#039; =&gt; $estoque

]);

return $stmt-&gt;rowCount() &gt; 0 ? true : false;

}

public function incrementarEstoque($id, $quantidade) {

$sql = &quot;UPDATE produtos SET estoque = estoque + :qtd WHERE id = :id&quot;;

$stmt = $this-&gt;pdo-&gt;prepare($sql);

return $stmt-&gt;execute([

&#039;:id&#039; =&gt; $id,

&#039;:qtd&#039; =&gt; $quantidade

]);

}

// Uso:

if ($produto-&gt;atualizar(1, &#039;Notebook Gamer&#039;, 3500.00, 5)) {

echo &quot;Atualizado com sucesso!&quot;;

} else {

echo &quot;Nenhum registro foi modificado.&quot;;

}

?&gt;</code></pre>

<p>O método <code>rowCount()</code> informa quantas linhas foram afetadas. Útil para validar se a atualização realmente ocorreu.</p>

<h2>DELETE: Removendo Registros</h2>

<p>Delete é irreversível. Implemente confirmações, logs ou soft delete (marcar como inativo) em sistemas críticos.</p>

<pre><code class="language-php">&lt;?php

public function deletar($id) {

$sql = &quot;DELETE FROM produtos WHERE id = :id&quot;;

$stmt = $this-&gt;pdo-&gt;prepare($sql);

return $stmt-&gt;execute([&#039;:id&#039; =&gt; $id]) &amp;&amp; $stmt-&gt;rowCount() &gt; 0;

}

// Soft delete (recomendado):

public function desativar($id) {

$sql = &quot;UPDATE produtos SET ativo = 0, deletado_em = NOW() WHERE id = :id&quot;;

$stmt = $this-&gt;pdo-&gt;prepare($sql);

return $stmt-&gt;execute([&#039;:id&#039; =&gt; $id]);

}

// Uso em controlador:

if ($_SERVER[&#039;REQUEST_METHOD&#039;] === &#039;POST&#039; &amp;&amp; isset($_POST[&#039;deletar_id&#039;])) {

$id = (int)$_POST[&#039;deletar_id&#039;];

if ($produto-&gt;deletar($id)) {

header(&#039;Location: /produtos&#039;);

}

}

?&gt;</code></pre>

<p>Soft delete preserva dados para auditoria e recuperação. Sempre valide o ID antes de deletar para evitar exclusões acidentais.</p>

<h2>Conclusão</h2>

<p>Três pontos essenciais aprendidos: <strong>Prepared statements são não-negociáveis</strong> para segurança contra SQL Injection; <strong>organize o código em classes</strong> separando lógica de banco e regras de negócio; <strong>valide sempre o número de linhas afetadas</strong> para confirmar sucesso real de operações, especialmente em UPDATE e DELETE. Com PDO bem implementada, você tem código seguro, testável e portável entre diferentes bancos de dados.</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 PHP PDO</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://www.php.net/manual/pt_BR/pdo.prepared-statements.php" target="_blank" rel="noopener noreferrer">PHP.NET: Prepared Statements</a></li>

<li><a href="https://www.digitalocean.com/community/tutorials/php-crud" target="_blank" rel="noopener noreferrer">Digital Ocean: PHP CRUD com PDO</a></li>

</ul>

Comentários

Mais em PHP

Dominando Cache em PHP: Redis, Memcached e Cache de Opcode com OPcache em Projetos Reais
Dominando Cache em PHP: Redis, Memcached e Cache de Opcode com OPcache em Projetos Reais

Cache em PHP: Redis, Memcached e OPcache O cache é um dos pilares da otimizaç...

Guia Completo de PHPUnit na Prática: Testes Unitários em PHP
Guia Completo de PHPUnit na Prática: Testes Unitários em PHP

O que é PHPUnit e Por Que Usar PHPUnit é o framework de testes unitários mais...

Arrays em PHP: Indexados, Associativos e Multidimensionais: Do Básico ao Avançado
Arrays em PHP: Indexados, Associativos e Multidimensionais: Do Básico ao Avançado

Arrays Indexados Arrays indexados são a forma mais básica de estrutura de dad...