Mi is az a PDO?

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.

Mást se szeretnél jobban, mint azonnal értesülni a friss tartalmakról? A legjobb helyen jársz! Feliratkozhatsz az oldal RSS feed-jére vagy követheted a blogot Twitteren.