IN() no PDO: como passar um array sem dor e erros

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

«Posso vincular um array a uma condição IN()?» — a pergunta que atormenta um em cada dois desenvolvedores PHP

\n\n

Você já escreveu uma consulta como SELECT * FROM users WHERE id IN (?) e tentou passar um array via bindValue()? Se sim — você conhece bem aquela sensação de frustração quando o PDO retorna apenas uma linha em vez de todas as necessárias. Ou pior — lança um erro.

\n\n

Esta pergunta no Stack Overflow acumulou milhares de visualizações, e não é à toa. Parece simples: passou o array, obteve o resultado. Mas o PDO (PHP Data Objects) é uma ferramenta rigorosa. Ele não sabe "desdobrar" arrays em uma lista de valores para IN() automaticamente. E é aí que começa a parte interessante: os desenvolvedores cometem os principais erros que vamos analisar hoje. E o principal — aprenderemos a evitá-los.

\n\n

Neste artigo, não vamos apenas dar uma solução pronta. Vamos percorrer o caminho do código incorreto para o seguro, performático e elegante. Vamos lá!

\n\n

Erro nº1: Passagem ingênua do array via bindValue

\n\n

O "ralo" mais comum — tentar passar o array diretamente para bindValue().

\n\n
// ❌ INCORRETO\n$ids = [1, 2, 3, 5];\n$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN (?)");\n$stmt->bindValue(1, $ids, PDO::PARAM_STR);\n$stmt->execute();\n$users = $stmt->fetchAll();
\n\n

O que acontece? O PHP converte o array em uma string "Array", e a consulta se torna WHERE id IN ("Array"). O resultado — zero linhas ou erro, dependendo do driver. O PDO simplesmente não entende que o array precisa ser desmembrado em placeholders individuais.

\n\n

Por que isso acontece? O PDO espera um valor escalar (string, número, null). Um array é um tipo composto e não é adequado para binding direto.

\n\n

Como corrigir?

\n

É necessário criar manualmente placeholders para cada elemento do array. Sem mágica, apenas código.

\n\n
// ✅ CORRETO\n$ids = [1, 2, 3, 5];\n$placeholders = implode(',', array_fill(0, count($ids), '?'));\n$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN ($placeholders)");\n$stmt->execute($ids);\n$users = $stmt->fetchAll();
\n\n

Aqui criamos uma string do tipo ?,?,?,? e passamos o array diretamente para execute(). O PDO substituirá os valores na ordem. Simples e seguro.

\n\n

Erro nº2: Ignorar os tipos de dados

\n\n

Suponha que você esteja usando placeholders nomeados. E surge a tentação de fazer assim:

\n\n
// ❌ INCORRETO\n$ids = [1, 2, 3];\n$placeholders = [];\nforeach ($ids as $i => $id) {\n    $placeholders[] = ":id_$i";\n}\n$sql = "SELECT * FROM users WHERE id IN (" . implode(',', $placeholders) . ")";\n$stmt = $pdo->prepare($sql);\nforeach ($ids as $i => $id) {\n    $stmt->bindValue(":id_$i", $id, PDO::PARAM_INT);\n}\n$stmt->execute();
\n\n

Parece tudo certo. Mas há um detalhe: se o array estiver vazio, a consulta se torna WHERE id IN (), o que causa um erro de sintaxe SQL. O segundo problema — se o array contiver strings e você especificou PDO::PARAM_INT, o PDO pode convertê-las para zero.

\n\n

Solução: sempre verifique se o array está vazio e determine o tipo dinamicamente.

\n\n
// ✅ CORRETO\n$ids = [1, 2, 3];\nif (empty($ids)) {\n    return []; // ou lançar uma exceção\n}\n$placeholders = [];\nforeach ($ids as $i => $id) {\n    $placeholders[] = ":id_$i";\n}\n$sql = "SELECT * FROM users WHERE id IN (" . implode(',', $placeholders) . ")";\n$stmt = $pdo->prepare($sql);\nforeach ($ids as $i => $id) {\n    $type = is_int($id) ? PDO::PARAM_INT : PDO::PARAM_STR;\n    $stmt->bindValue(":id_$i", $id, $type);\n}\n$stmt->execute();
\n\n

Erro nº3: Injeção SQL através de "escape" manual

\n\n

Alguns desenvolvedores, em desespero, escrevem algo como

Blogs

Book Recommendations