PHP.de Wissenssammlung

PDO (PHP Data Objects)

Verbindung herstellen
Prepared Statements
mit und ohne Parameter, Varianten der Parameterbindung
Verweise

Dieser Überblick beschäftigt sich mit konkreten Anwendungsbeispielen von PDO bzw. Prepared Statements mittels PDO. Weitere grundsätzliche Informationen dazu sind in der PHP-Doku zu finden:

Verbindung herstellen

Nachfolgend wird die Verbindung zum DBMS hergestellt.

$dsn  = 'mysql:dbname=test;host=localhost;charset=utf8';
$user = 'root';
$pass = '';
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
    PDO::ATTR_EMULATE_PREPARES => false
];
$pdo = new PDO($dsn, $user, $pass, $options);

Hinweise zu den Optionsparametern

Je nach Vorlieben bzw. Entwicklungsstil können Parameter auch anderweitig gesetzt werden. Nachfolgend zwei übliche Beispiele - weitere Parameter sind in der Doku zu finden.

Wiederverwendung der Verbindung

Benötigt eine Funktion oder ein Objekt eine DB-Verbindung, so wird die bestehende PDO-Instanz $pdo als Parameter übergeben. Dieses Prinzip nennt sich Dependency Injection. In den folgenden Beispielen wird weiters typehinting verwendet.

Beispiel für eine Funktion

function getUsernameById($userID, PDO $pdo) {
    // ...
}


// Funktionsaufruf
$username = getUsernameById(23, $pdo);

Beispiel für eine Klasse

class User
{
    private $pdo; // Eigenschaft deklarieren

    public function __construct(PDO $pdo) {
        // PDO-Objekt an die Eigenschaft übergeben
        // diese steht nun in der ganzen Klasse
        // per $this->pdo zur Verfügung.
        $this->pdo = $pdo;
    }
    // ...
}


// Aufruf / Instantiierung
$user = new User($pdo);

Prepared Statements

Dazu aus der PHP-Doku

Die Parameter für Prepared Statements müssen nicht maskiert werden. Der Treiber übernimmt das automatisch. Wenn eine Anwendung ausschließlich Prepared Statements benutzt, kann sich der Entwickler sicher sein, dass keine SQL-Injection auftreten wird. (Wenn aber trotzdem andere Teile der Abfrage aus nicht zuverlässigen Eingaben generiert werden, ist dies immer noch möglich.)

`Backticks` vermeiden
Einer der Vorteile von PDO ist die Portabilität zwischen den unterschiedlichen DBMS. Um dem zu entsprechen, sollten in der Query keine (MySQL spezifischen) `Backticks` verwendet werden. Daraus resultiert, das auf die Benennung der Spalten entsprechend zu achten ist, um nicht mit den reservierten Keywords des jeweilig verwendeten DBMS zu kollidieren.

Query ohne Parameter

$sql = "SELECT username FROM user";
$stmt = $pdo->prepare($sql);

// Namen einzeln ausgeben
if ($stmt->execute()) {
    while ($row = $stmt->fetch()) {
        echo $row->username."<br>\n";
    }
}

// ODER

// alle Daten in ein Array überführen
$stmt->execute();
$arr = $stmt->fetchAll();
print_r($arr);

Mit Parameter - Bindung der Parameter

Nachfolgende Möglichkeiten bestehen u.a., um die Parameter an das Statement zu binden.

Parameter einzeln binden

// Query vorbereiten
$sql = "SELECT username, gender FROM user WHERE username = :username AND gender = :gender";
$stmt = $pdo->prepare($sql);

// Parameter übergeben und verarbeiten
$username = 'Joachim';
$gender = 'M';

$stmt->bindParam(':username', $username);
$stmt->bindParam(':gender',   $gender);

if ($stmt->execute()) {
    $row = $stmt->fetch();
    echo $row->username;
}

Hinweis
Die Parameterbindung kann alternativ zu bindParam() mit bindValue() vorgenommen werden. Die Unterschiede sind in diesem stackoverflow-Beitrag mittels kurzen Beispielen dargestellt.

Parameter per Array binden

// Query vorbereiten
$sql = "SELECT username, gender FROM user WHERE username = :username AND gender = :gender";
$stmt = $pdo->prepare($sql);

// Parameter übergeben und verarbeiten
$username = 'Sarah';
$gender = 'F';

$aParams = array(':username' => $username, ':gender' => $gender);
$stmt->execute($aParams);

echo $stmt->rowCount();

Daten aus Array in DB schreiben

Um Daten mittels Prepared Statements aus einem Array in die DB zu schreiben, kann man folgenden Ansatz nutzen. Verwendet wird dazu wieder das oben erstellte PDO-Objekt $pdo mit der DB-Verbindung. Das Beispiel entstammt diesen PHP.de-Thread.

// Temporäre Tabelle zum Testen des Scripts
$pdo->query("
    CREATE TEMPORARY TABLE temp (
        id INT NOT NULL AUTO_INCREMENT,
        vorname VARCHAR(255) NOT NULL,
        nachname VARCHAR(255) NOT NULL,
        PRIMARY KEY (id)
    )
");

// unser Daten-Array
$aData = [
    ['vorname' => 'Hans',   'nachname' => 'Maier'],
    ['vorname' => 'Peter',  'nachname' => 'Müller'],
    ['vorname' => 'Robert', 'nachname' => 'Kinz']
];

// in DB schreiben
$sql = "
    INSERT INTO temp (" . implode(", ", array_keys($aData[0])) . ")
    VALUES (" . implode(", ", array_fill(0, count($aData[0]), "?")) . ")
";
$stmt = $pdo->prepare($sql);

foreach ($aData as $row) {
    $stmt->execute(array_values($row));
}

// Test - Daten wieder ausgeben
$result = $pdo->query("SELECT id, vorname, nachname FROM temp");
print_r( $result->fetchAll(PDO::FETCH_ASSOC) );
/*
Array
(
    [0] => Array
        (
            [id] => 1
            [vorname] => Hans
            [nachname] => Maier
        )

    [1] => Array
        (
            [id] => 2
            [vorname] => Peter
            [nachname] => Müller
        )

    [2] => Array
        (
            [id] => 3
            [vorname] => Robert
            [nachname] => Kinz
        )

)
*/

Dieser Beitrag ist fertiggestellt und wurde zuletzt von hausl bearbeitet.

An diesem Beitrag waren bisher beteiligt: hausl