PDO

Z PHPEdia.pl

PDO to skrót od PHP Data Objects. Jest to obiektowy, zunifikowany interfejs do komunikacji z najpopularniejszymi bazami danych wprowadzony w PHP 5.1. Jeżeli masz tę lub nowszą wersję, powinieneć mieć pełen dostęp do oferowanych przez niego możliwości.

Spis treści

Co oferuje PDO?

W przeciwieństwie do większości starych rozszerzeń, PDO nie jest związany z żadnym konkretnym systemem bazodanowym. Zamiast tego, pozwala łączyć się na równych prawach z szeregiem różnych systemów, np. MySQL, PostgreSQL oraz SQLite. Kolejną wyróżniającą go cechą jest obiektowa architektura, cechująca jedynie dotąd nakładki pisane w czystym PHP (np. ADOdb). PDO zapewnia:

  1. Możliwość wykonywania zapytań SQL oraz pobierania wyników.
  2. Jednolity mechanizm konfiguracji.
  3. Nowoczesny mechanizm raportowania błędów wykorzystujący wyjątki.
  4. Niezależność interfejsu od konkretnej bazy danych.
  5. Emulację wybranych elementów nieobsługiwanych przez niektóre bazy danych (głównie podpinanie parametrów).

Należy mieć jednak świadomość, iż PDO nie stanowi kompletnej warstwy komunikacji z bazą danych. Nie posiada on bowiem części możliwości, które można spotkać w tego typu rozwiązaniach takich, jak profilowanie zapytań oraz cache'owanie ich wyników.

Kto korzysta z PDO?

PDO staje się coraz popularniejsze i coraz więcej liczących się aplikacji zaczyna wykorzystywać go jako bazę dla swoich własnych rozwiązań. Tak jest w przypadku Zend Frameworka czy systemu ORM Doctrine. Spotkać go można także w wielu mniejszych projektach. Z tego powodu warto zapoznać się z nim i rozważyć przesiadkę ze starszych interfejsów, które być może będą powoli wycofywane z biegiem czasu.

Jak zacząć?

Jądro PDO jest napisane w języku C i jest domyślnie włączone w większości dystrybucji PHP, dlatego nie musisz dołączać ani ściągać żadnych dodatkowych bibliotek. Połączenie się z istniejącą bazą danych nie jest trudne - polega na utworzeniu obiektu klasy PDO. Jako argument konstruktora podajemy tzw. DSN, który identyfikuje używany przez nas system bazodanowy oraz parametry połączenia. Poniższy przykład pokazuje, jak połączyć się z bazą MySQL

<?php
try
{
   $pdo = new PDO('mysql:dbname=moja_baza;host=localhost', 'user', 'login');
   $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $exception)
{
   echo 'Blad polaczenia z baza danych: '.$exception->getMessage();
}

Jak widać, DSN nie jest trudny do zbudowania, lecz jego szczegółowa budowa zależy od konkretnej bazy danych. Szczegóły konstruowania DSN-ów dla innych systemów bazodanowych podane są w dokumentacji. Jeśli PDO nie będzie mógł połączyć się z bazą danych, wygeneruje wyjątek PDOException. Ponadto, tuż po połączeniu warto przy pomocy metody setAttribute() ustawić, aby następne błędy także były zgłaszane jako wyjątki, gdyż domyślnie PDO przełącza się po nawiązaniu połączenia w tryb cichy.

Wysyłanie zapytań

Do wysłania zapytań możemy użyć jednej z dwóch metod: query() oraz exec() wchodzących w skład obiektu klasy PDO. Pierwsza z nich przeznaczona jest dla zapytań SELECT, gdyż generuje obiekt PDOStatement, dzięki któremu możemy pobrać wyniki:

<?php
try
{
   $pdo = new PDO('mysql:dbname=moja_baza;host=localhost', 'user', 'login');
   $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
   $stmt = $pdo->query('SELECT id, nazwa, opis FROM produkty');
   echo '<ul>';
   foreach($stmt as $row)
   {
       echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
   }
   $stmt -> closeCursor();
}
catch(PDOException $exception)
{
   echo 'Blad polaczenia z baza danych: '.$exception->getMessage();
}

Ważne, aby po pobraniu wszystkich wyników nie zapomnieć o wywołaniu metody closeCursor(), która zamknie kursor. PDO domyślnie nie wykonuje w tle żadnych operacji w stylu buforowania zbioru wyników, co zwiększa wydajność, dlatego nie możemy tutaj rekurencyjnie wywoływać zapytań. Jeśli jakiś zbiór wyników jest otwarty, próba wysłania do bazy w tym czasie kolejnego zapytania nie powiedzie się.

Metoda exec() przeznaczona jest dla zapytań typu INSERT czy UPDATE, gdzie bardziej interesuje nas liczba zmodyfikowanych wierszy:

<?php
try
{
   $pdo = new PDO('mysql:dbname=moja_baza;host=localhost', 'user', 'login');
   $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
   echo 'Zaktualizowanych wierszy: '.$pdo->exec('UPDATE produkty SET `wizyty` = (`wizyty` + 1)');
}
catch(PDOException $exception)
{
   echo 'Blad polaczenia z baza danych: '.$exception->getMessage();
}

Podpinanie parametrów

Jedną z bardziej użytecznych właściwości PDO jest możliwość podpinania danych do zapytań. Twórcy posunęli się nawet do tego stopnia, że jeżeli jakiś system bazodanowy nie wspiera tego rozwiązania, sterownik PDO dla niego musi zapewnić odpowiednią emulację. Podpinanie zapytań zapewnia przejrzysty i bardziej odporny na błędy mechanizm umieszczania danych ze skryptu w zapytaniach SQL. Zamiast wstawiać je bezpośrednio, w samym zapytaniu umieszczamy odpowiednie wstawki, zaś dalej podpinamy pod nie właściwe dane dodatkowymi metodami. Połączeniem danych z zapytaniem zajmuje się już baza danych, z uwzględnieniem ich typu. Co ważniejsze, zapewnia to także odporność na ataki typu SQL Injection! W przypadku seryjnego wykonywania tego samego zapytania z różnymi zestawami danych, pozwala również zwiększyć wydajność. W praktyce wygląda to następująco:

<?php
try
{
   $pdo = new PDO('mysql:dbname=moja_baza;host=localhost', 'user', 'login');
   $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
   $stmt = $pdo->prepare('SELECT id, nazwa, opis FROM produkty WHERE `cena` > :cena');
   $stmt->bindValue(':cena', 50.00, PDO::PARAM_STR);
   $stmt->execute();
 
   echo '<ul>';
   foreach($stmt as $row)
   {
       echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
   }
   $stmt -> closeCursor();
}
catch(PDOException $exception)
{
   echo 'Blad polaczenia z baza danych: '.$exception->getMessage();
}

Tym razem zapytanie wysyłamy metodą prepare(), zaś podpinanie danych odbywa się przy użyciu metody PDOStatement::bindValue(). Na końcu musimy pamiętać o wywołaniu execute(). Podpinanie działa zarówno dla zapytań SELECT, jak też INSERT/UPDATE/DELETE.

Podsumowanie

Artykuł ten przedstawia jedynie krótki wstęp do PDO. Biblioteka posiada znacznie więcej możliwości i zachęcamy do dalszego zapoznania się z nimi.

Przydatne linki

  1. Dokumentacja PDO
  2. Artykuł poświęcony PDO na Wikibooks