Fundamentos do PHP

0/25 aulas0%
pratica

Operações CRUD I: SELECT e INSERT com PDO

Aprenda sobre operações crud i: select e insert com pdo

50 min
Aula 2 de 5

Aula 5.1: Operações CRUD I: SELECT e INSERT com PDO

Olá, estudante! 👋 Bem-vindo(a) à primeira aula prática sobre persistência de dados. Hoje, vamos mergulhar nas operações fundamentais de interação com bancos de dados, focando em SELECT (leitura) e INSERT (inserção) usando a poderosa extensão PDO do PHP.

🚀 1. Introdução: O que é CRUD e por que PDO?

Quando falamos em aplicações que interagem com dados, a sigla CRUD é onipresente. Ela representa as quatro operações básicas que podemos realizar em um banco de dados:

  • Create (Criar) - INSERT
  • Read (Ler) - SELECT
  • Update (Atualizar) - UPDATE
  • Delete (Deletar) - DELETE

Nesta aula, vamos nos concentrar nas duas primeiras: CREATE (através do INSERT) e READ (através do SELECT).

Para interagir com bancos de dados no PHP, a extensão PDO (PHP Data Objects) é a maneira recomendada e mais robusta. Ela oferece uma camada de abstração que permite trabalhar com diversos tipos de bancos de dados (MySQL, PostgreSQL, SQLite, etc.) usando uma API unificada. Além disso, o PDO é fundamental para a segurança, especialmente contra ataques de Injeção SQL, através do uso de prepared statements.

Vamos começar! 🛠️

📚 2. Conectando ao Banco de Dados com PDO

Antes de realizar qualquer operação, precisamos estabelecer uma conexão com o banco de dados. O PDO facilita isso, mas é crucial lidar com possíveis erros.

2.1. Configuração do Ambiente

Para esta aula, você precisará:

  • Um servidor web (Apache/Nginx) com PHP instalado.
  • Um banco de dados, como MySQL ou SQLite. Recomendo MySQL/MariaDB para um ambiente de desenvolvimento.
  • Certifique-se de que a extensão pdo_mysql (ou pdo_sqlite, etc.) esteja habilitada no seu php.ini.

2.2. Estabelecendo a Conexão

A conexão com o PDO é feita instanciando a classe PDO. É uma boa prática envolver a conexão em um bloco try-catch para capturar exceções, como credenciais incorretas ou banco de dados indisponível.

<?php
 
$host = 'localhost';
$db   = 'meu_banco'; // Nome do seu banco de dados
$user = 'root';      // Usuário do banco de dados
$pass = 'sua_senha'; // Senha do banco de dados
$charset = 'utf8mb4';
 
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // Lança exceções em caso de erro
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,       // Retorna resultados como array associativo por padrão
    PDO::ATTR_EMULATE_PREPARES   => false,                  // Desabilita a emulação de prepared statements (melhor para segurança e performance)
];
 
try {
    $pdo = new PDO($dsn, $user, $pass, $options);
    echo "Conexão estabelecida com sucesso! 🎉\n";
} catch (\PDOException $e) {
    // Lança uma exceção mais genérica para evitar expor detalhes do banco de dados
    throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
 
// O objeto $pdo agora está pronto para ser usado
?>

Explicação:

  • $dsn: Data Source Name. É uma string que especifica o tipo de banco de dados (mysql), o host, o nome do banco (dbname) e o charset.
  • $options: Um array de opções para configurar o comportamento do PDO.
    • PDO::ATTR_ERRMODE: Define como o PDO lida com erros. PDO::ERRMODE_EXCEPTION é o mais recomendado, pois lança exceções que podem ser capturadas.
    • PDO::ATTR_DEFAULT_FETCH_MODE: Define o modo padrão para buscar resultados. PDO::FETCH_ASSOC é muito comum, retornando arrays associativos (chave-valor).
    • PDO::ATTR_EMULATE_PREPARES: Desabilitar a emulação de prepared statements é uma boa prática, pois permite que o banco de dados prepare a query, aumentando a segurança.

2.3. Criando uma Tabela de Exemplo

Para nossos exemplos, vamos criar uma tabela simples chamada usuarios.

CREATE TABLE usuarios (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nome VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    data_cadastro DATETIME DEFAULT CURRENT_TIMESTAMP
);

Você pode executar este SQL diretamente no seu cliente MySQL (phpMyAdmin, MySQL Workbench, etc.) ou via PHP:

<?php
// ... código de conexão PDO ...
 
try {
    $pdo->exec("
        CREATE TABLE IF NOT EXISTS usuarios (
            id INT AUTO_INCREMENT PRIMARY KEY,
            nome VARCHAR(100) NOT NULL,
            email VARCHAR(100) UNIQUE NOT NULL,
            data_cadastro DATETIME DEFAULT CURRENT_TIMESTAMP
        );
    ");
    echo "Tabela 'usuarios' verificada/criada com sucesso! ✅\n";
} catch (\PDOException $e) {
    echo "Erro ao criar tabela: " . $e->getMessage() . "\n";
}
?>

📝 3. Operação INSERT (Criar Dados)

A operação INSERT é usada para adicionar novas linhas (registros) a uma tabela. Com PDO, usaremos prepared statements para garantir a segurança e a correta manipulação dos dados.

3.1. Inserindo um Único Registro

<?php
// ... código de conexão PDO ...
 
$nome = "Alice Silva";
$email = "alice.silva@example.com";
 
try {
    // 1. Preparar a query SQL com placeholders
    $stmt = $pdo->prepare("INSERT INTO usuarios (nome, email) VALUES (:nome, :email)");
 
    // 2. Vincular os valores aos placeholders
    $stmt->bindParam(':nome', $nome);
    $stmt->bindParam(':email', $email);
 
    // 3. Executar a query
    $stmt->execute();
 
    // Opcional: Obter o ID do último registro inserido
    $lastId = $pdo->lastInsertId();
 
    echo "Usuário '{$nome}' inserido com sucesso! ID: {$lastId} ✨\n";
 
} catch (\PDOException $e) {
    if ($e->getCode() == 23000) { // Código de erro para violação de UNIQUE constraint (email duplicado)
        echo "Erro: E-mail '{$email}' já cadastrado. 🚫\n";
    } else {
        echo "Erro ao inserir usuário: " . $e->getMessage() . "\n";
    }
}
?>

Explicação:

  • $pdo->prepare(): Prepara a instrução SQL. Usamos named placeholders (:nome, :email), que são mais legíveis e seguros do que concatenar strings.
  • $stmt->bindParam(): Vincula uma variável PHP a um placeholder no prepared statement. Isso é crucial para prevenir Injeção SQL, pois o PDO garante que os valores sejam tratados como dados, e não como parte do comando SQL.
  • $stmt->execute(): Executa a instrução preparada.
  • $pdo->lastInsertId(): Retorna o ID do último registro inserido por uma instrução INSERT.

3.2. Inserindo Múltiplos Registros (Exemplo com array para execute)

Uma alternativa ao bindParam é passar um array associativo diretamente para o método execute(), o que é útil quando você tem muitos parâmetros ou os dados já estão em um array.

<?php
// ... código de conexão PDO ...
 
$usuariosParaInserir = [
    ['nome' => 'Bruno Costa', 'email' => 'bruno.costa@example.com'],
    ['nome' => 'Carla Dias', 'email' => 'carla.dias@example.com'],
    ['nome' => 'Alice Silva', 'email' => 'alice.silva@example.com'] // Este vai falhar por e-mail duplicado
];
 
$stmt = $pdo->prepare("INSERT INTO usuarios (nome, email) VALUES (:nome, :email)");
 
foreach ($usuariosParaInserir as $usuario) {
    try {
        $stmt->execute($usuario); // Passa o array diretamente
        $lastId = $pdo->lastInsertId();
        echo "Usuário '{$usuario['nome']}' inserido com sucesso! ID: {$lastId} ✨\n";
    } catch (\PDOException $e) {
        if ($e->getCode() == 23000) {
            echo "Erro: E-mail '{$usuario['email']}' já cadastrado para '{$usuario['nome']}'. 🚫\n";
        } else {
            echo "Erro ao inserir usuário '{$usuario['nome']}': " . $e->getMessage() . "\n";
        }
    }
}
?>

📖 4. Operação SELECT (Ler Dados)

A operação SELECT é usada para recuperar dados de uma ou mais tabelas. Novamente, usaremos prepared statements para consultas com condições.

4.1. Selecionando Todos os Registros

<?php
// ... código de conexão PDO ...
 
try {
    $stmt = $pdo->query("SELECT id, nome, email, data_cadastro FROM usuarios");
 
    echo "\n--- Todos os Usuários Cadastrados ---\n";
    while ($row = $stmt->fetch()) {
        echo "ID: {$row['id']}, Nome: {$row['nome']}, Email: {$row['email']}, Cadastro: {$row['data_cadastro']}\n";
    }
    echo "-------------------------------------\n";
 
} catch (\PDOException $e) {
    echo "Erro ao buscar usuários: " . $e->getMessage() . "\n";
}
?>

Explicação:

  • $pdo->query(): Usado para executar instruções SQL que não possuem parâmetros (como SELECT * FROM table sem WHERE). Ele retorna um objeto PDOStatement.
  • $stmt->fetch(): Recupera a próxima linha de um conjunto de resultados. Por padrão (devido a PDO::FETCH_ASSOC nas opções de conexão), retorna um array associativo. Retorna false quando não há mais linhas.

4.2. Selecionando um Registro Específico com Prepared Statement

Quando você precisa filtrar dados (usando WHERE), é essencial usar prepared statements.

<?php
// ... código de conexão PDO ...
 
$idBuscado = 2; // ID do usuário que queremos buscar
$emailBuscado = "bruno.costa@example.com"; // Email do usuário que queremos buscar
 
try {
    // Buscar por ID
    $stmt = $pdo->prepare("SELECT id, nome, email, data_cadastro FROM usuarios WHERE id = :id");
    $stmt->bindParam(':id', $idBuscado, PDO::PARAM_INT); // PDO::PARAM_INT para garantir que é um inteiro
    $stmt->execute();
    $usuarioPorId = $stmt->fetch();
 
    if ($usuarioPorId) {
        echo "\n--- Usuário encontrado por ID ({$idBuscado}) ---\n";
        echo "ID: {$usuarioPorId['id']}, Nome: {$usuarioPorId['nome']}, Email: {$usuarioPorId['email']}\n";
    } else {
        echo "\nUsuário com ID {$idBuscado} não encontrado. 🤷‍♀️\n";
    }
 
    // Buscar por E-mail
    $stmt = $pdo->prepare("SELECT id, nome, email, data_cadastro FROM usuarios WHERE email = :email");
    $stmt->execute([':email' => $emailBuscado]); // Usando array para execute()
    $usuarioPorEmail = $stmt->fetch();
 
    if ($usuarioPorEmail) {
        echo "\n--- Usuário encontrado por E-mail ({$emailBuscado}) ---\n";
        echo "ID: {$usuarioPorEmail['id']}, Nome: {$usuarioPorEmail['nome']}, Email: {$usuarioPorEmail['email']}\n";
    } else {
        echo "\nUsuário com E-mail '{$emailBuscado}' não encontrado. 🤷‍♂️\n";
    }
 
} catch (\PDOException $e) {
    echo "Erro ao buscar usuário: " . $e->getMessage() . "\n";
}
?>

Explicação:

  • $stmt->bindParam(':id', $idBuscado, PDO::PARAM_INT): Além de vincular a variável, especificamos o tipo de dado (PDO::PARAM_INT). Isso adiciona uma camada extra de segurança e ajuda o PDO a otimizar a comunicação com o banco de dados.
  • $stmt->execute([':email' => $emailBuscado]): Demonstra novamente o uso de um array associativo para vincular parâmetros ao execute().

4.3. Recuperando Múltiplos Registros de Uma Vez (fetchAll)

Se você precisa de todas as linhas do resultado de uma vez (por exemplo, para iterar sobre elas mais tarde ou passá-las para uma view), fetchAll() é a função ideal.

<?php
// ... código de conexão PDO ...
 
$termoBusca = "%Silva%"; // Busca por nomes que contenham "Silva"
 
try {
    $stmt = $pdo->prepare("SELECT id, nome, email FROM usuarios WHERE nome LIKE :termo");
    $stmt->execute([':termo' => $termoBusca]);
    $usuariosEncontrados = $stmt->fetchAll(); // Recupera todas as linhas como um array de arrays
 
    if ($usuariosEncontrados) {
        echo "\n--- Usuários com '{$termoBusca}' no nome ---\n";
        foreach ($usuariosEncontrados as $usuario) {
            echo "ID: {$usuario['id']}, Nome: {$usuario['nome']}, Email: {$usuario['email']}\n";
        }
        echo "-------------------------------------------\n";
    } else {
        echo "\nNenhum usuário encontrado com '{$termoBusca}' no nome. 😔\n";
    }
 
} catch (\PDOException $e) {
    echo "Erro ao buscar usuários por termo: " . $e->getMessage() . "\n";
}
?>

🧪 5. Exercícios Práticos

Agora é a sua vez de colocar a mão na massa! Crie um novo arquivo PHP e implemente as seguintes tarefas.

🎯 Lista de Tarefas:

  • 1. Configuração Inicial:

    • Crie um banco de dados chamado minha_aplicacao_php.
    • Adapte o código de conexão PDO para se conectar a este novo banco de dados.
    • Crie uma tabela chamada produtos com as seguintes colunas:
      • id (INT, AUTO_INCREMENT, PRIMARY KEY)
      • nome (VARCHAR(100), NOT NULL)
      • descricao (TEXT, NULL)
      • preco (DECIMAL(10, 2), NOT NULL)
      • estoque (INT, NOT NULL, DEFAULT 0)
      • data_criacao (DATETIME, DEFAULT CURRENT_TIMESTAMP)
  • 2. Inserir Produtos:

    • Escreva um script PHP para inserir 3 produtos diferentes na tabela produtos.
    • Use prepared statements com named placeholders.
    • Exiba o ID do produto inserido após cada INSERT.
    • Tente inserir um produto com o mesmo nome (se você adicionou uma constraint UNIQUE ao nome, observe o erro).
  • 3. Listar Todos os Produtos:

    • Escreva um script PHP que selecione e exiba todos os produtos da tabela produtos.
    • Formate a saída de forma legível (ex: "ID: 1, Nome: Camiseta, Preço: 29.90, Estoque: 50").
  • 4. Buscar Produtos por Preço:

    • Escreva um script PHP que busque e exiba todos os produtos cujo preço seja maior que um valor específico (ex: 25.00).
    • Use prepared statements para a condição WHERE.
  • 5. Buscar Produto por ID:

    • Escreva um script PHP que busque um único produto pelo seu id.
    • Se o produto for encontrado, exiba seus detalhes. Caso contrário, exiba uma mensagem informando que o produto não foi encontrado.
    • Use prepared statements e PDO::PARAM_INT para o ID.
  • 6. (Desafio Opcional) Função de Conexão:

    • Crie uma função conectarBanco() que encapsule a lógica de conexão PDO e retorne o objeto $pdo.
    • Use esta função em todos os seus scripts para evitar repetição de código.

🏁 6. Resumo e Próximos Passos

Nesta aula, você aprendeu os fundamentos da interação com bancos de dados usando PDO no PHP:

  • Conexão Segura: Como estabelecer uma conexão robusta com o banco de dados usando try-catch e configurações recomendadas.
  • Operação INSERT: Como adicionar novos registros a uma tabela de forma segura usando prepared statements e bindParam() ou passando um array para execute().
  • Operação SELECT: Como ler dados de uma tabela, seja todos os registros, um registro específico ou um conjunto de registros filtrados, utilizando query(), prepare(), execute(), fetch() e fetchAll().
  • Segurança: A importância dos prepared statements para prevenir ataques de Injeção SQL.

Na próxima aula, continuaremos explorando as operações CRUD, focando em UPDATE (atualização) e DELETE (exclusão) de dados, completando assim o ciclo básico de manipulação de dados.

Até lá, pratique bastante os exercícios! Se tiver dúvidas, não hesite em consultar a documentação oficial do PHP sobre PDO: https://www.php.net/manual/pt_BR/book.pdo.php

Bons estudos! 🚀

© 2025 Escola All Dev. Todos os direitos reservados.

Operações CRUD I: SELECT e INSERT com PDO - Fundamentos do PHP | escola.all.dev.br