Gondolom sokaknak megfordult a fejében (akik 2 percnél többet töltöttek el a PHP tanulmányozásával és adatbázis kapcsolatot is próbáltak létesíteni), hogy kellene valami egységesebb felület (mondjuk egy adatbázis objektum), ha például a rendszerünket MySQL alapokról PostgreSQL-re akarnánk átvinni, vagy csak egyszerűen szeretnénk, hogy valahogy kinézzen az a kód. Gondolom akadnak olyanok is, akik fogták magukat és megírták ezt a bizonyos objektumot (vagy objektumokat), vagy olyanok, akik a PEAR által kínált megoldást találták megfelelőnek. Viszont a PHP 5.1-es verziójától már beépített megoldás is van erre az égető problémára egy kiterjesztés-csoport személyében.

A PDO nem más mint egy objektum az adatbázis kapcsolatok, lekérdezések, stb. kényelmes, hatékony, átlátható kezelésére. No de lássunk egy "ilyen volt, ilyen lett" példát, csak a mondani valóm nyomatékosítása érdekében (aztán majd rátérünk a PDO mélyrehatóbb elemzésére):

$conn = mysql_connect('localhost', 'user', 'password');
mysql_select_db('database', $conn);

$query = mysql_query(" SELECT * FROM `table` ", $conn);
while ($row = mysql_fetch_assoc($query)) {
    print_r($row);
}
mysql_close($conn);

Nézzük csak, mi lett belőle:

$db = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
foreach ($db->query(" SELECT * FROM `table` ") as $row) {
    print_r($row);
}
$db = NULL;

Ízlés kérdése, de nekem az utóbbi jobban tetszik. Talán érdemes lenne az osztályok szerkezetének a vizsgálatával folytatni a dolgokat. A rendszer három osztályból áll, amik a PDO, PDOStatement és a PDOException. Az első fontosabb függvényei a query, prepare, exec, beginTransaction, commit. Míg a másodiké (természetesen mindkét esetben a teljesség igénye nélkül) a fetch, fetchAll, rowCount, bindParam, execute. A harmadik osztály (a nevéből talán nem nehéz rájönni) a kivételkezelést hivatott elősegíteni. Amint az sejthető, a dolog például úgy működik, hogy a PDO osztály query függvénye visszaad egy PDOStatement típusú érétket, aminek függvényeivel megkaphatjuk a kívánt sorokat vagy dob egy PDOException típusú kivételt.

Tranzakciók

Aki annak idejé olvasta Polaa PostgreSQL bejegyzés-sorozatát, annak nem lehet annyira ismeretlen ez a fogalom. A dolog lényege dióhéjban annyi, hogy egy blokkban vagy mindegyik SQL utasítás végrehajtódik, vagy pedig egyik sem. Eléggé szemléletes a mindenhol felhozott banki átutalásos példa, ahol az egyik lekérdezés leveszi "A" ügyfél számlájáról a pénzt, a második pedig rárakja "B" számlájára. Ez esetben azt szeretnénk, hogy ha nem sikerül az első lépés, akkor a második se hajtódjon végre. Nézzünk kódot, mert az érdekesebb:

try {
    $db = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $db->beginTransaction();
    $db->exec(" UPDATE `accounts` SET `account_value`=`account_value`-100 WHERE `account_id`='1' ");
    $db->exec(" UPDATE `accounts` SET `account_value`=`account_value`+100 WHERE `account_id`='2' ");
    $db->commit();
} catch (PDOException $e) {
    $db->rollBack();
}
setAttribute
Az adatbázis kezelő objektum tulajdonságait tudjuk vele beállítani különböző, a PDO objektumban tárolt konstansokkal. Ez esetben az lett beállítva, hogy - az alapértelmezettől eltérően - kivételt dobjon hiba esetén.
beginTransaction
Jelzi, a tranzakció kezdetét.
commit
A tranzakció lefuttatása.
rollBack
A tranzakció visszavonása.

Előkészített lekérdezések

Ez egy tipikusan olyan dolog volt, amit annak idején hiányoltam MySQL-ben és, ami miatt sikerült elég gyorsan megkedvelnem a PostgreSQL-t. A dolog már a neve alapján is teljesen egyértelmű, de a kód is önmagáért fog beszélni, tehát csapjunk is a lecsóba:

$db = new PDO('pgsql:host=localhost;dbname=database;user=user;password=password');
$pre = $db->prepare(' INSERT INTO "attrs" ("id", "name") VALUES (:id, :name) ');
$pre->execute(array(':id' => '1', ':name' => '12'));
$pre->execute(array(':id' => '2', ':name' => '43'));

A PDO prepare részének az is a nagy előnye, hogy elég sokféleképpen használható. Itt van például egy másik megoldás is, ahol a kérdőjelek sorrendben cserélődnek le a tömb egyes elemeire, ugyanazt elérve mint az előző kódblokkban (az adatbázis kapcsolatot elhagytam):

$pre = $db->prepare(' INSERT INTO "attrs" ("id", "name") VALUES (?, ?) ');
$pre->execute(array('1', '12'));
$pre->execute(array('2', '43'));

Jöjjön még egy megoldás két variációja, ami mégjobban leegyszerüsíti az előkészített lekérdezések használatát (a végeredmény ugyanaz, mint az előző esetekben).

$pre = $db->prepare(' INSERT INTO "attrs" ("id", "name") VALUES (:id, :value) ');
$pre->bindParam(':id', $id);
$pre->bindParam(':value', $value);

$id = '1';
$value= '12';
$pre->execute();
$id = '2';
$value= '43';
$pre->execute();

Vagy a másik megoldás (ismét kérdőjeleket használva a beillesztések helyeinek meghatározására):

$pre = $db->prepare(' INSERT INTO "attrs" ("id", "name") VALUES (?, ?) ');
$pre->bindParam(1, $id);
$pre->bindParam(2, $value);

$id = '1';
$value = '12';
$pre->execute();
$id = '2';
$value = '43';
$pre->execute();

Azt hiszem ennyi lenne a kis ismertető a PDO kiterjesztéssel kapcsolatban. Kedvcsinálásnak talán megteszi, mindenesetre mégegyszer megjegyezném, hogy az igazi ereje a dolognak abban rejlik (azon felül, hogy a kódot átláthatóbbá teszi, aminek az erejét sosem szabad lebecsülni), hogy akár egy sor átírása elég lehet ahhoz, hogy egy rendszert például MySQL alapúról PostgreSQL alapúvá tegyünk.