1. Die Grundlagen: PDO und DSN
PDO steht für PHP Data Objects. Es ist eine moderne, objektorientierte Schnittstelle, um von PHP aus auf Datenbanken zuzugreifen. Der größte Vorteil von PDO ist, dass es eine einheitliche API bietet, egal welche Datenbank du verwendest (MySQL, PostgreSQL, SQLite etc.). Du könntest die Datenbank austauschen, ohne deinen ganzen Code ändern zu müssen.
Der DSN (Data Source Name) ist ein String, der der PDO-Klasse sagt, welche Datenbank sie ansprechen soll und wo sie diese findet. Er hat einen festen Aufbau:
datenbanktyp:host=serveradresse;dbname=datenbankname;charset=zeichensatz
- Für MySQL könnte ein DSN so aussehen:mysql:host=localhost;dbname=workopia_db;charset=utf8mb4
2. Die Verbindung herstellen (Der PDO-Konstruktor)
Um eine Verbindung herzustellen, erstellst du ein neues Objekt der PDO-Klasse. Du übergibst den DSN sowie Benutzername und Passwort. Am wichtigsten ist jedoch das vierte Argument: ein Array mit Optionen.
PHP
$dsn = 'mysql:host=localhost;dbname=deine_db;charset=utf8mb4';
$dbUser = 'dein_benutzer';
$dbPass = 'dein_passwort';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Wirft Fehler als Exceptions
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // Standard-Fetch-Modus
PDO::ATTR_EMULATE_PREPARES => false, // Nutzt echte Prepared Statements
];
try {
$pdo = new PDO($dsn, $dbUser, $dbPass, $options);
} catch (\PDOException $e) {
// Im Fehlerfall: Verbindung abbrechen und Fehlermeldung ausgeben.
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
Was die Optionen bedeuten:
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION: Das ist die wichtigste Einstellung! Sie sorgt dafür, dass Datenbankfehler nicht nur als Warnung ausgegeben, sondern alsPDOExceptiongeworfen werden. Das erlaubt dir, Fehler mittry...catch-Blöcken sauber abzufangen.PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC: Hiermit legst du fest, in welchem Format du deine Ergebnisse standardmäßig erhalten möchtest.PDO::FETCH_ASSOC: Gibt jede Zeile als assoziatives Array zurück (['spaltenname' => 'wert']). Das ist der gängigste Modus.PDO::FETCH_OBJ: Gibt jede Zeile als anonymes Standard-Objekt zurück ($zeile->spaltenname).
3. Daten abfragen (Der sichere Weg: Prepared Statements)
Das ist der Weg, den du immer verwenden solltest, wenn Benutzerdaten (aus $_GET, $_POST etc.) in der Abfrage vorkommen.
Reihenfolge: prepare() → execute() → fetch()
prepare($sql): Du schickst die SQL-Anweisung mit Platzhaltern (:nameoder?) an die Datenbank. Die Datenbank validiert die Anweisung und bereitet sie vor. Du bekommst einPDOStatement-Objekt zurück.execute($params): Du führst das vorbereitete Statement aus und übergibst die Werte für die Platzhalter als Array.fetch()oderfetchAll(): Du holst die Ergebnisse ab.
PHP
// Angenommen, wir suchen nach einem Job mit einer bestimmten ID
$id = 123;
// 1. Prepare
$sql = "SELECT * FROM listings WHERE id = :id";
$statement = $pdo->prepare($sql);
// 2. Execute
$params = [':id' => $id];
$statement->execute($params);
// 3. Fetch
$listing = $statement->fetch(); // Holt nur EINE Zeile
4. Ergebnisse holen: fetch() vs. fetchAll()
Nachdem du execute() aufgerufen hast, hast du mehrere Möglichkeiten, an die Daten zu kommen.
fetch(): Holt die nächste einzelne Zeile aus dem Ergebnis. Wenn du es erneut aufrufst, holt es die nächste Zeile, bis keine mehr da ist (dann gibt esfalsezurück). Ideal, wenn du nur einen einzigen Datensatz erwartest (z.B. „SELECT * FROM users WHERE id = ?“).fetchAll(): Holt alle Zeilen des Ergebnisses auf einmal und gibt sie als Array zurück. Wenn deinDEFAULT_FETCH_MODEPDO::FETCH_ASSOCist, bekommst du ein Array von assoziativen Arrays. Ideal, wenn du eine Liste von Dingen anzeigen willst.rowCount(): Gibt die Anzahl der betroffenen Zeilen einerDELETE,INSERToderUPDATEAnweisung zurück. FürSELECTist es nicht immer zuverlässig.
5. Der schnelle Weg: query()
Wenn deine SQL-Abfrage keine variablen Daten enthält, kannst du die Abkürzung query() verwenden. Sie führt prepare() und execute() quasi in einem Schritt aus.
PHP
// Sicher, weil keine Benutzereingaben drin sind
$statement = $pdo->query("SELECT * FROM listings LIMIT 6");
// Danach kannst du direkt die Ergebnisse holen
$listings = $statement->fetchAll();
Dies ist funktional fast identisch mit:
$listings = $db->prepare(„SELECT * FROM listings LIMIT 6“)->execute()->fetchAll();
6. Zusammenspiel mit extract()
Hier wird die Wahl des Fetch-Modes entscheidend. Stell dir vor, du übergibst einen Job-Datensatz an einen View:
Szenario 1: PDO::FETCH_ASSOC (Standard)
PHP
// Controller
$listing = $statement->fetch(PDO::FETCH_ASSOC); // Ergibt ['title' => 'PHP Dev', 'city' => 'Berlin']
loadView('listing-details', ['listing' => $listing]);
// View
extract($data); // Erstellt eine Variable $listing, die ein Array ist.
echo $listing['title']; // Zugriff über Array-Schlüssel
Szenario 2: PDO::FETCH_OBJ
PHP
// Controller
$listing = $statement->fetch(PDO::FETCH_OBJ); // Ergibt ein Objekt
loadView('listing-details', ['listing' => $listing]);
// View
extract($data); // Erstellt eine Variable $listing, die ein Objekt ist.
echo $listing->title; // Zugriff über Objekt-Eigenschaft
Der Objekt-Stil ($listing->title) wird oft als sauberer und moderner empfunden.
7. Die ultimative Vorlage: Eine Database-Klasse
Am besten packst du die ganze Logik in eine Klasse, damit du sie nicht immer wieder schreiben musst. Diese Klasse kannst du dann in deinem Projekt wiederverwenden.
Database.php (z.B. im Hauptverzeichnis deines Projekts)
PHP
<?php
class Database {
public $conn;
/**
* Konstruktor für die Database-Klasse
* @param array $config
*/
public function __construct($config)
{
$dsn = "mysql:host={$config['host']};port={$config['port']};dbname={$config['dbname']};charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, // Hier auf OBJ für saubere Syntax
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$this->conn = new PDO($dsn, $config['username'], $config['password'], $options);
} catch (PDOException $e) {
throw new Exception("Datenbankverbindung fehlgeschlagen: {$e->getMessage()}");
}
}
/**
* Führt eine Abfrage mit Prepared Statements aus
* @param string $query
* @param array $params
* @return PDOStatement
*/
public function query($query, $params = [])
{
try {
$sth = $this->conn->prepare($query);
$sth->execute($params);
return $sth;
} catch (PDOException $e) {
throw new Exception("Abfrage fehlgeschlagen: {$e->getMessage()}");
}
}
}
Wie du die Vorlage nutzt:
- Konfigurationsdatei erstellen (z.B.
config/db.php)PHP
<?php return [ 'host' => 'localhost', 'port' => 3306, 'dbname' => 'workopia_db', 'username' => 'root', 'password' => 'dein_passwort' ]; - In deinem Controller verwenden
PHP
require basePath('Database.php'); $config = require basePath('config/db.php'); $db = new Database($config); // Alle Listings holen $listings = $db->query("SELECT * FROM listings")->fetchAll(); // Ein einzelnes Listing holen $id = 1; $listing = $db->query("SELECT * FROM listings WHERE id = :id", [':id' => $id])->fetch(); // Daten an den View übergeben loadView('listings/index', [ 'listings' => $listings, 'listing' => $listing ]);
Diese Vorlage gibt dir eine robuste, sichere und wiederverwendbare Basis für alle deine Datenbankinteraktionen.
