Fundamentos do PHP
Operações CRUD I: SELECT e INSERT com PDO
Aprenda sobre operações crud i: select e insert com pdo
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(oupdo_sqlite, etc.) esteja habilitada no seuphp.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çãoINSERT.
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 (comoSELECT * FROM tablesemWHERE). Ele retorna um objetoPDOStatement.$stmt->fetch(): Recupera a próxima linha de um conjunto de resultados. Por padrão (devido aPDO::FETCH_ASSOCnas opções de conexão), retorna um array associativo. Retornafalsequando 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 aoexecute().
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
produtoscom 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)
- Crie um banco de dados chamado
-
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
UNIQUEao nome, observe o erro).
- Escreva um script PHP para inserir 3 produtos diferentes na tabela
-
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").
- Escreva um script PHP que selecione e exiba todos os produtos da tabela
-
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.
- Escreva um script PHP que busque e exiba todos os produtos cujo preço seja maior que um valor específico (ex:
-
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_INTpara o ID.
- Escreva um script PHP que busque um único produto pelo seu
-
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.
- Crie uma função
🏁 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-catche 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 paraexecute(). - 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()efetchAll(). - 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! 🚀