Einführung in PDO

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • 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.

    Quellcode

    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.

    Quellcode

    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. }
    Alles anzeigen


    == 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).

    Quellcode

    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.

    Quellcode

    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).

    Quellcode

    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);
    Alles anzeigen


    == 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.

    Quellcode

    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. }
    Alles anzeigen


    == 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:

    Quellcode

    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:

    Quellcode

    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. }
    Alles anzeigen


    Das Beispiel erweitern wir wie folgt:

    Quellcode

    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:

    Quellcode

    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:

    Quellcode

    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.

    22.702 mal gelesen

Kommentare 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]