PDO یک افزونه سبک و قدرتمند PHP برای به دیتابیسه . از خصوصیات خوب این افزونه که از نسخه 5.1 روی PHP نصب شده موارد زیر است:
- پشتیبانی از دیتابیسهای متنوع از جمله MySQL، MsSQL، SQLite و غیره با توابع ثابت.
امکان فوق العاده PDO که اجازه میده تا بدون تغییر کدها، دیتابیس رو تغییر بدیم. یعنی مثلا اگر Applicationای با MySQL ساخته باشیم و تحت شرایطی مجبور به تغییر دیتابیس به MsSQL باشیم، اگر سینتکس کوئری ها مشکلی ایجاد نکنه، کافیه دیتابیس رو تعویض کنیم و همین. برای سیستمهای بزرگ این یک مزیت خیلی مهمه. - پشتیبانی از Exceptionهای PHP.
Exceptionها امکان کنترل و بدست گیری خطاها رو به برنامه نویس میده. PDO امکان کنترل خطاهای دیتابیس رو هم بهمون میده. - پشتیبانی از Prepared Statement و Stored Procedure ها و Multiple Recordset.
این سه مورد هیچ کدوم توسط توابع کثافت MySQL اجرا نمیشند. PDO مورد آخر رو در حال حاضر برای MySQL پشتیبانی نمی کنه. - طراحی شده به شکل کلاس.
قابلیت مهمی که امکان گسترش و شخصی سازی PDO رو میده مثلا رفتار توابعش رو تغییر بدیم یا توابع جدیدی بهش اضافه کنیم و در واقع همه امکانات شی گرایی رو باهاش داشته باشیم.
[LIST]PDO از سه تا کلاس تشکیل شده: - کلاس اصلی به نام PDO که حاوی توابع اصلی مثل اجرای کوئری و اتصال و غیره است.
- کلاس با نام PDOStatement حاوی توابع برای پردازش و بهره گیری از کوئری های اجرا شده است مثل fetch.
- کلاس PDOException برای بدست گیری خطاهای رخ داده.
[/LIST]
این موارد همه در ادامه، به همراه آموزش ابتدایی، بیشتر توضیح داده خواهند شد.
نکته: کلاس حاوی تعدادی متد (Method) است که مانند تابع (Function) عمل میکنند. اطلاق عنوان تابع به یک متد از نظر تخصصی صحیح نیست ولی برای فهم روانتر مقاله از عبارت تابع بجای متد استفاده شده است. نحوه اتصال
با توجه به اینکه PDO یک کلاس است اتصال به دیتابیس با نمونه گیری این کلاس شروع میشه:
$pdo = new PDO('mysql:dbname=mydatabase;host=localhost', 'db_username', 'db_password');
با اینکار ما به دیتابیس مورد نظرمون متصل شدیم. پارامتر اول فرمت خاصی داره. همونجور که میبینی در پارامتر اول، ما نوع دیتابیس که MySQL هست رو هم مشخص کردیم. برای قطع اتصال هم کافیه این شی رو از بین ببریم. اینجوری:
$pdo = null;
[color=#696969][FONT=arial]اجرای کوئری[/FONT][/color]
با سه نوع تابع میشه یک کوئری رو اجرا کرد.
کوئری های آماده یا ساده توسط تابع PDO::query اجرا میشند و یک شی از کلاس PDOStatement برمیگردونند.
$stmt = $pdo->query("SELECT id, name, age FROM users");
متغیر stmt$ یک نمونه کلاس PDOStatement هست که توابع خودش رو داره. میخوایم این کوئری رو Fetch کنیم. برای اینکار چند مدل تابع وجود داره. تابع PDOStatement::fetch که در حالت پیشفرض مشابه تابع mysql_fetch_arrayعمل میکنه.
$row = $stmt->fetch();
echo "Name: ".$row['name'];
echo "Name: ".$row[1];
echo "Age: ".$row['age'];
echo "Age: ".$row[2];
توسط پارامتر میشه به این تابع فهموند که چه مدلی آرایه ای تولید کنه:
$assoc_row = $stmt->fetch(PDO::FETCH_ASSOC);
echo "Name: ".$assoc_row['name'];
echo "Age: ".$assoc_row['age'];
$num_row = $stmt->fetch(PDO::PDO::FETCH_NUM);
echo "Name: ".$num_row[1];
echo "Age: ".$num_row[2];
$obj_row = $stmt->fetch(PDO::PDO::FETCH_OBJ);
echo "Name: ".$obj_row->name;
echo "Age: ".$obj_row->age;
تابع PDOStatement::fetchAll مشابه تابع قبل عمل میکنه ولی یک آرایه برمیگردونه از سطرهای بدست اومده به اضافه اینکه حافظه ی اشغال شده برای کوئری (داخل PDO) رو هم آزاد میکنه.
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($rows as $row) {
echo "Name: ".$row['name'];
echo "Age: ".$row['age'];
}
مشکلی که PDO داره اینه که نمیشه هنگام fetch شدن یک کوئری، کوئری دیگه ای رو fetch کرد! یعنی تابع fetch دوم کد زیر هیچی برنمیگردونه:
$select = $pdo->query("SELECT id,name FROM parents");
while($parent = $select->fetch(PDO::FETCH_ASSOC)) {
// ...
$stmt = $pdo->query("SELECT name FROM children WHERE parent=$parent[id]");
$child = $stmt->fetch(PDO::FETCH_ASSOC);
echo "Child is ".$child['name']; // Output: "Child is "
// ...
}
البته هیچ خطایی هم رخ نداده. PDO میگه: "مگه من چند تا دست دارم؟ موقع Fetch کردن یک کوئری یه کوئری دیگه رو هم Fetch کنم؟ نکنه فکر کردی من کامپیوترم؟"برای حل این مشکل چند تا راه داریم یکیش استفاده از تابع PDOStatement::fetchAll است:
$select = $pdo->query("SELECT id,name FROM parents");
$parents = $select->fetchAll(PDO::FETCH_ASSOC);
foreach($parents as $parent) {
// ...
$stmt = $pdo->query("SELECT name FROM children WHERE parent=$parent[id]");
$child = $stmt->fetch(PDO::FETCH_ASSOC);
echo "Child is ".$child['name']; // Output: "Child is baby"
// ...
}
PDOStatement::fetchAll توانایی های دیگه ای هم توی ساختن آرایه داره که مثلا کلید هر سطر فلان فیلدش باشه و غیره. بعد از fetch کردن بهتره شی PDOStatement ساخته شده رو پاک کنیم بعضی مواقع باید این کار رو بکنیم برای این کار، یکی از دو روش زیر رو انجام میدیم:
$stmt = null;
$stmt->closeCursor();
حالت اول کلا ریشه ی شی رو میکنه ولی حالت دوم فقط حافظه رو تخلیه میکنه و هنوز میشه از شی استفاده کرد.
تابع PDOStatement::fetchColumn هم فقط مقدار یک ستون رو برمیگردونه. اگر هیچ پارامتری نگیره ستون اول، در غیر اینصورت ستون مشخص شده:
$select = $pdo->query("SELECT id,name FROM parents");
echo "ID: ".$select->fetchColumn();
echo "Name: ".$select->fetchColumn(1);
همونجور که میبینی شماره 1 یعنی ستون دوم یعنی شماره ستونها از صفر شروع میشه. کاربرد این تابع زمانی هست که کوئری رو فقط برای یک مقدار و ستون اجرا کردیم مثل این:
echo "Name: ".$pdo->query("SELECT name FROM users WHERE id=7")->fetchColumn();
توابع مهم دیگه شی PDOStatement تا اینجا تابع rowCount و nextRowset هستند.اولی مثل mysql_num_rows تعداد سطرهای بدست اومده رو میده و دومی وقتی بکار میاد که کوئری بجای یک دسته سطر، چند دسته سطر رو برگردونه. این حالت توی Stored Procedureها رخ میده که من بتونم با یک کوئری چند مدل RecordSet یا دسته سطر داشته باشم. این تابع در MySQL فعلا کار خاصی نمی کنه!
حالت دوم اجرای کوئری ها، مواقعی است که مقدار برگشتی نداریم مثل عملیات INSERT یا DELETE و غیره. تابع PDO::exec مثل PDO::query ، کوئری اجرا میکنه ولی فقط تعداد سطرهایی رو برمیگردونه که تحت تاثیر قرار گرفته اند. حسن این تابع اینه که از تابع PDO::query سریعتره.
$num = $pdo->exec("UPDATE users SET level=1 WHERE age<19");
echo $num ." user(s) were changed";
پس برای مواقعی که نیاز به خروجی و fetch نداریم بهتره از این تابع استفاده کنیم.
- پردازش و تحلیل کوئری در دیتابیس.
- بررسی کوتیشن ها بصورت خودکار برای حل مسئله SQL Injection.
زمانی که لازم داریم تا یک کوئری رو بر اساس مقادیری به دفعات اجرا کنیم، حالت عادی بهینه نیست. PDO امکان میده تا کوئری رو با پارامترهای مشخص ابتدا معرفی کنیم تا در دیتابیس پردازش بشه و بعد هر تعداد که میخوام اجراش کنیم. تابع PDO::prepare این کار رو میکنه و مثل PDO::query یک شی PDOStatement برمیگردونه که هنوز کامل اجرا نشده:
$stmt = $pdo->prepare("SELECT * FROM users WHERE id=:id");
ادامه دارد...