Mi is az a PDO?
Adatbázis kezelés és PHP
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.