Signatur
Beschreibung
mysqli_stmt kapselt ein vorbereitetes SQL-Statement, das mit Platzhaltern (?) parametrisiert wird. Der große Vorteil liegt in der klaren Trennung von SQL-Struktur und Nutzdaten: Das Statement wird einmal kompiliert und kann mehrfach mit unterschiedlichen Parametern ausgeführt werden, was sowohl die Performance verbessert als auch SQL-Injection-Angriffe strukturell verhindert.
Objekte dieser Klasse werden in der Regel nicht direkt instanziiert, sondern über mysqli::prepare() oder die prozedurale Funktion mysqli_prepare() erzeugt. Anschließend werden Parameter mit bind_param() gebunden, das Statement mit execute() ausgeführt und Ergebnisse mit bind_result() oder get_result() abgerufen.
Typische Einsatzszenarien sind INSERT-, UPDATE-, DELETE- und SELECT-Abfragen mit variablen Nutzereingaben, z. B. in Login-Formularen, Suchfunktionen oder bei Masseninserts in Schleifen. Prepared Statements sind gegenüber direktem Zusammensetzen von SQL-Strings immer die sicherere und oft auch schnellere Alternative.
Seit PHP 8.1 werden Warnungen erzeugt, wenn Methoden auf einem bereits geschlossenen Statement aufgerufen werden. Mit PHP 8.2 wurde das Fehlerverhalten weiter vereinheitlicht; es wird empfohlen, den Fehlerbehandlungsmodus auf MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT zu setzen, um Exceptions statt stiller Fehler zu erhalten.
Beispiele
SELECT-Abfrage mit Prepared Statement und bind_result()
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'user', 'password', 'testdb');
$stmt = $mysqli->prepare('SELECT id, username FROM users WHERE email = ?');
$email = 'alice@example.com';
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->bind_result($id, $username);
while ($stmt->fetch()) {
echo "ID: $id, Benutzername: $username\n";
}
$stmt->close();
$mysqli->close();
INSERT in einer Schleife (Masseninsert)
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'user', 'password', 'testdb');
$users = [
['bob@example.com', 'Bob'],
['carol@example.com', 'Carol'],
['dave@example.com', 'Dave'],
];
$stmt = $mysqli->prepare('INSERT INTO users (email, username) VALUES (?, ?)');
foreach ($users as [$email, $username]) {
$stmt->bind_param('ss', $email, $username);
$stmt->execute();
echo "Eingefügt mit ID: " . $stmt->insert_id . "\n";
}
$stmt->close();
$mysqli->close();
SELECT mit get_result() und assoziativem Array
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('localhost', 'user', 'password', 'testdb');
$stmt = $mysqli->prepare('SELECT id, username, email FROM users WHERE id > ?');
$minId = 10;
$stmt->bind_param('i', $minId);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
printf("[%d] %s <%s>\n", $row['id'], $row['username'], $row['email']);
}
$stmt->close();
$mysqli->close();
// Wichtig · Fallstricke
Sicherheit: Prepared Statements schützen strukturell vor SQL-Injection, da Nutzdaten niemals direkt in den SQL-Text eingefügt werden. Dennoch sollte die Ausgabe von Daten immer noch mit htmlspecialchars() oder einem Template-System escaped werden, um XSS zu verhindern.
Typkennzeichner bei bind_param(): s = String, i = Integer, d = Double/Float, b = Blob (wird in Paketen gesendet). Falscher Typ kann zu Datenverlust oder unerwartetem Verhalten führen.
get_result() erfordert den nativen MySQL-Treiber (mysqlnd). Ist er nicht verfügbar, muss bind_result() verwendet werden.
Ressourcen schließen: Nach Verwendung sollten $stmt->close() und $mysqli->close() aufgerufen werden, um Datenbankverbindungen und Servercursor freizugeben.