IN() in PDO: Wie man ein Array ohne Schmerz und Fehler übergibt

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

„Can I bind an array to an IN() condition?“ – eine Frage, die jeden zweiten PHP-Entwickler quält

\n\n

Haben Sie jemals eine Abfrage wie SELECT * FROM users WHERE id IN (?) geschrieben und versucht, ein Array über bindValue() zu übergeben? Wenn ja, kennen Sie genau dieses Gefühl der Enttäuschung, wenn PDO nur eine einzige Zeile zurückgibt, anstatt aller benötigten. Oder noch schlimmer – einen Fehler wirft.

\n\n

Diese Frage auf Stack Overflow hat tausende Aufrufe gesammelt, und das nicht ohne Grund. Es scheint so einfach: Array übergeben, Ergebnis erhalten. Aber PDO (PHP Data Objects) ist eine strenge Sache. Es kann Arrays nicht automatisch in eine Werteliste für IN() „entfalten“. Und hier beginnt das Interessante: Entwickler erfinden Top-Fehler, die wir heute analysieren. Und vor allem – lernen wir, sie zu vermeiden.

\n\n

In diesem Artikel geben wir nicht nur eine fertige Lösung. Wir gehen den Weg von falschem Code zu sicherem, performantem und schönem Code. Los geht‘s!

\n\n

Fehler Nr. 1: Naive Übergabe eines Arrays über bindValue

\n\n

Der häufigste „Stolperstein“ – der Versuch, ein Array direkt in bindValue() zu füttern.

\n\n
// ❌ FALSCH\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

Was passiert? PHP wandelt das Array in einen String "Array" um, und die Abfrage wird zu WHERE id IN ("Array"). Das Ergebnis – null Zeilen oder ein Fehler, abhängig vom Treiber. PDO versteht einfach nicht, dass das Array in einzelne Platzhalter aufgeteilt werden muss.

\n\n

Warum passiert das? PDO erwartet einen skalaren Wert (String, Zahl, null). Ein Array ist ein zusammengesetzter Typ und eignet sich nicht für direktes Binden.

\n\n

Wie behebt man das?

\n

Man muss manuell Platzhalter für jedes Element des Arrays erstellen. Keine Magie, nur Code.

\n\n
// ✅ RICHTIG\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

Hier erstellen wir einen String der Form ?,?,?,? und übergeben das Array direkt an execute(). PDO setzt die Werte der Reihe nach ein. Einfach und sicher.

\n\n

Fehler Nr. 2: Ignorieren von Datentypen

\n\n

Angenommen, Sie verwenden benannte Platzhalter. Und dann kommt die Versuchung, Folgendes zu tun:

\n\n
// ❌ FALSCH\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

Das scheint alles richtig zu sein. Aber es gibt einen Haken: Wenn das Array leer ist, wird die Abfrage zu WHERE id IN (), was einen SQL-Syntaxfehler verursacht. Das zweite Problem – wenn das Array Strings enthält, Sie aber PDO::PARAM_INT angegeben haben, kann PDO diese auf null setzen.

\n\n

Lösung: Überprüfen Sie immer das Array auf Leerheit und bestimmen Sie den Typ dynamisch.

\n\n
// ✅ RICHTIG\n$ids = [1, 2, 3];\nif (empty($ids)) {\n    return []; // oder eine Exception werfen\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

Fehler Nr. 3: SQL-Injection durch „manuelles“ Escaping

\n\n

Einige Entwickler schreiben in ihrer Verzweiflung etwas wie

Blogs

Buchempfehlungen