Introduction: "Why doesn't PDO understand my array?"
\nEvery PHP developer working with databases sooner or later encounters a situation where they need to execute a query with the IN() operator. It seems simple enough: pass an array of values and get filtered data. But this is where the main pitfall lies.
Here is a classic example that comes to a beginner's mind:
\n<?php\n$ids = [1, 2, 3, 5];\n$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN (:ids)");\n$stmt->execute([':ids' => $ids]); // Error!\n?>\nAnd then PDO throws an error: "Array to string conversion" or simply returns an empty result. Why does this happen? PDO does not know how to "unfold" arrays into SQL queries. It expects a scalar value for each named placeholder, not a whole array.
\nIn this article, we will break down the top mistakes developers make when trying to bind an array to IN(), and show you the correct, safe, and efficient solutions.
Mistake #1: Naively passing an array to execute()
\nThis is the most common mistake. The developer thinks PDO will figure out to substitute each value from the array into the IN() condition. But, as we've already established, PDO doesn't work that way.
What it looks like in code
\n<?php\n$ids = [10, 20, 30];\n$stmt = $pdo->prepare("SELECT * FROM products WHERE id IN (:ids)");\n$stmt->execute([':ids' => $ids]); // Fatal error\n?>\nResult: An error or warning about converting an array to a string. Even if the code "slips through", PDO will substitute the word "Array" into the query — and you'll get WHERE id IN ('Array'), which is meaningless.
Why does this happen? PDO requires that each placeholder corresponds to a single value. An array is not a value, but a set of values. PDO cannot and should not guess what you want to do.
\n\nMistake #2: Using bindValue() with an array
\nSometimes developers try to trick PDO by using bindValue():
<?php\n$ids = [1, 2, 3];\n$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN (:ids)");\n$stmt->bindValue(':ids', $ids, PDO::PARAM_STR); // Error!\n$stmt->execute();\n?>\nThe problem is the same: bindValue() expects a scalar value. The array will be converted to the string "Array", and the query will not execute correctly. The third parameter (PDO::PARAM_STR) doesn't help — it only specifies the data type, but doesn't change the logic of working with an array.
Mistake #3: Direct concatenation (SQL injection)
\nIn desperation, some developers take the path of least resistance — they simply insert the array into the query using implode():
<?php\n$ids = [1, 2, 3];\n$ids_str = implode(',', $ids);\n$stmt = $pdo->query("SELECT * FROM users WHERE id IN ($ids_str)"); // Dangerous!\n?>\nWhy is this dangerous? If the values in the array come from the user (e.g., from GET parameters or a form), an attacker could pass 1; DROP TABLE users; --. The query would become IN (1; DROP TABLE users; --), and your database would be destroyed. This is a classic SQL injection.
Even if you are sure the data is safe, this practice is bad form. One day you will forget to check the data source, and the consequences will be catastrophic.
\n\nThe Correct Solution: Dynamic Placeholders
\nNow for the good news. PDO allows you to create placeholders dynamically. You need to generate a string with the required number of ? or :id1, :id2, ... and pass the array of values separately.
Method 1: Using positional placeholders (?)
\nThis is the simplest and most popular method:
\n<?php