Einführung in PDO

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • PDO ist die moderne Datenbankschnittstelle von PHP5. Manch geneigten Umsteiger überfordet PDO mit dem vermeintlich großen Funktionsumfang. Hier werden die wichtigsten Funktion erläutert.
    PDO(PHP Data Object) ist der moderne Weg mit PHP5 auf die Datenbank zuzugreifen. Es bietet eine Abstraktionsschicht für den Datenzugriff. Unabhängig vom verwendeten DBMS können die selben Funktionen verwenden.
    PDO räumt außerdem mit vielen Sicherheitsängsten auf, die man von anderen Datenbank-Schnittstellen kennt. Die vielen Wege die teilweise zum selben Ergebnis führen schrecken viele Programmierer ab, daher soll dieses Tutorial einen konsistenten Weg liefern.
    Konfiguration
    Eine gängige Art die Konfigurationvariablen zu hinterlegen ist eine finale Klasse mit Konstanten. Sie benötigt relativ wenig Prozess Overhead.

    Source Code

    1. final class Configuration {
    2. const DB_HOST='localhost';
    3. const DB_DATABASE='datebase';
    4. const DB_PORT=3306;
    5. const DB_USER='database_user';
    6. const DB_PASSWORD='database_password';
    7. }


    == Verbindung herstellen ==
    Einleitend wurde erläutert, dass PDO eine Abstraktionsschicht für den Datenbankzugriff bereitstellt. Durch Abstraktion folgert Einschränkung - nämlich auf den Nenner des schwächsten unterstützen DBMS. Aus mehreren Gründen macht es Sinn den Datenbankzugriff weiter zu kapseln.
    Wir erstellen uns daher eine neue Klasse "MyDB" die als Singleton implementiert wird, somit wird verhindert, dass in der selben PHP Anwendung mehrmals die Verbindung hergestellt wird.
    Außerdem erstellen wir eine persistente Verbindung - das bietet sich bei den meisten Webanwendungen an.

    Source Code

    1. class MyDB {
    2. private static $db;
    3. static public function getInstance() {
    4. if(!self::$db) {
    5. self::$db = new PDO(
    6. 'mysql:host='.Configuration::DB_HOST.';dbname='.Configuration::DB_DATABASE.';port='.Configuration::DB_PORT,
    7. Configuration::DB_USER,
    8. Configuration::DB_PASSWORD,
    9. array(
    10. PDO::ATTR_PERSISTENT => true,
    11. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ,
    12. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    13. )
    14. );
    15. }
    16. return self::$db;
    17. }
    18. }
    Display All


    == Datenbankänderungen ==
    Die einfachste Form von Datenbankzugriffen stellt das Ändern kleiner Daten dar. Parameter die man per Formular übergibt oder über die URL erhält, werden als Array-Parameter durch das execute() Statement gebunden.
    Außerdem fällt auf, dass der SQL-String durch das prepare Statement vorbereitet wird. Das ist ein Performance Faktor, sollte man das selbe "Prepared Statement" mehrmals mit unterschiedlichen Parameter ausführen wollen (was ein extrem seltener Fall ist).

    Source Code

    1. $pdoparams = array(
    2. ':userid' => $_REQUEST['userid'],
    3. ':website' => 'http://www.easy-coding.de'
    4. );
    5. $sql = "UPDATE user
    6. SET website = :website
    7. WHERE userid = :userid
    8. LIMIT 1";
    9. $stmt = MyDB::getInstance()->prepare($sql);
    10. $stmt->execute($pdoparams);


    == Neue Datenbankeintrage: ID des Datensatzes ==
    Werden auto_increment (MySQL) oder SERIAL (postgreSQL) Felder genutzt, kümmert sich das DBMS bei neuen Einträgen um die neuen Primärschlüssel. Sie werden mit der Funktion lastInsertID abgefragt.

    Source Code

    1. $pdoparams = array(
    2. ':website' => 'http://www.easy-coding.de'
    3. );
    4. $sql = "INSERT INTO user
    5. (website)
    6. VALUES (:website)";
    7. $stmt = MyDB::getInstance()->prepare($sql);
    8. $stmt->execute($pdoparams);
    9. $userID = MyDB::getInstance()->lastInsertId();
    10. echo $userID;


    == Datenbankabfragen ==
    Datenbankabfragen werden genauso wie Änderungen konstruiert - einzig die zusätzliche Methode fetch() wird danach aufgerufen.
    Wir haben eingangs beim Konstruieren den Standard Fetch-Modus auf ASSOC geändert. Dadurch erhalten wir ein Array Objekt mit dem Spaltennamen als Schlüssel und dem Inhalt als Wert erhalten. Führen wir die fetch() Funktion mehrmals durch erhalten wir alle Zeilen (falls mehrere vorhanden sind).

    Source Code

    1. $pdoparams = array(
    2. ':userid' => $_REQUEST['userid']
    3. );
    4. $sql = "SELECT *
    5. FROM user
    6. WHERE userid = :userid ";
    7. $stmt = MyDB::getInstance()->prepare($sql);
    8. $stmt->execute($pdoparams);
    9. $row = $stmt->fetch();
    10. print_r($row);
    11. $row = $stmt->fetch();
    12. print_r($row);
    Display All


    == Mehrere Daten abfragen ==
    Häufig werden einfach alle Daten abgefragt, die man per SQL String definiert. Statt der Methode fetch() benutzt man dazu die Methode fetchAll(). Die Rückgabe der Funktion ist ein normales zweidimensionales Array, über das man mit foreach iterieren kann.

    Source Code

    1. $pdoparams = array(
    2. ':username' => "%".$_REQUEST['username']."%",
    3. ':minage' => $_REQUEST['minage'],
    4. ':maxage' => $_REQUEST['maxage']
    5. );
    6. $sql = "SELECT *
    7. FROM user
    8. WHERE username LIKE :username
    9. AND age BETWEEN :minage AND :maxage";
    10. $stmt = MyDB::getInstance()->prepare($sql);
    11. $stmt->execute($pdoparams);
    12. foreach($stmt->fetchAll() as $row) {
    13. print_r($row);
    14. }
    Display All


    == Kommaseparierte Liste mit IN ==
    MySQL und andere DBMS bieten die Möglichkeit kommaseparierte Listen mit IN zu verarbeiten.
    Der SQL String um die Benutzer 1,3 und 5 zu löschen würde folgendermaßen aussehen:

    Source Code

    1. DELETE FROM user
    2. WHERE userID IN (1,3,5)


    Um eine kommaseparierte Listen verarbeiten zu können kennt das PDO leider keine Möglichkeit.
    Die Klasse MyDB wird daher um eine spezielle implode Methode erweitert:

    Source Code

    1. class MyDB {
    2. private static $escapecounter = 0;
    3. ...
    4. static public function implode(&$pdoparams, $arr) {
    5. $tmp = array();
    6. foreach($arr as $val) {
    7. $key = ':implode'.self::$escapecounter++;
    8. $pdoparams[$key] = $val;
    9. $tmp[] = $key;
    10. }
    11. return implode(',', $tmp);
    12. }
    13. }
    Display All


    Das Beispiel erweitern wir wie folgt:

    Source Code

    1. $pdoparams = array();
    2. $sql = "DELETE FROM user
    3. WHERE userID IN (".MyDB::implode($pdoparams, array(1,3,5)).")";
    4. $stmt = MyDB::getInstance()->prepare($sql);
    5. $stmt->execute($pdoparams);


    Die Methode implode() liefert einen String mit Platzhaltern zurück:

    Source Code

    1. DELETE FROM user
    2. WHERE userID IN (:implode0,:implode1,:implode2)

    Zusätzlich wird das als Referenz übergebene Array $pdoparams um die Inhalte erweitert. Nach Ausführung von implode sieht das Array also wie folgt aus:

    Source Code

    1. Array (
    2. [:implode0] => 1
    3. [:implode1] => 3
    4. [:implode2] => 5
    5. )

    Das execute() bindet diese Parameter an den String und das Statement wird sicher ausgeführt. Die Lösung ist besser als sich den String mit PHP Stringfunktionen selbst zusammen zu bauen, da das PDO nur auf diese Art vor SQL Injections schützt.

    == Code Download ==
    Den fertigen Code von Klasse und dem letzten Beispiel gibt es zum Download unter demo.easy-coding.de/php/pdo/download.zip.

    17,647 times viewed

Comments 2

  • Torben Brodt -

    Bei extrem großen Datensätzen kann die fetchAll Methode Probleme bereiten, da alle Daten in ein einziges Array geladen wird - also gleichzeitig alles im Arbeitsspeicher gehalten wird.
    Ruft man fetch() einzeln auf, entspricht dies dem Vorgehen eines Iterators.
    Ich bin am überlegen ob man hier mit SPL nicht eine noch einfachere Syntax bauen könnte.
    Informationen dazu unter [url]http://www.phpro.org/tutorials/Introduction-to-SPL.html#8[/url]