انواع دریافت داده ها در PDO - قسمت اول

13 بهمن 1397
درسنامه درس 6 از سری آموزش PDO
PDO-Fetch-Data

با سلام، در این قسمت از سری آموزشی کار با رابط شیء گرای PDO قصد داریم انواع راه های دریافت داده در PDO را بررسی کنیم.

prepared statement و اجرای چند باره

برخی اوقات می توانید به جای اجرای چند باره ی یک کوئری، از prepared statement ها برای اجرای چند باره ی آن ها استفاده کنید.

بدین صورت سرعت اجرای کار را تا حدی بهبود می بخشید و همچنین کوئری ما یک بار بیشتر تجزیه (parse) نمی شود.

این قابلیت در صورتی که به ما اجازه می داد از آن ها در یک نمونه ی (instance) دیگر از PHP استفاده کنیم، بسیار کاربردی بود اما متاسفانه چنین نیست و شما تنها می توانید یک کوئری واحد را در یک instance واحد تکرار کنید.

البته چنین حالتی بسیار کم پیش می آید و معمولا تنها در هنگام INSERT ها و UPDATE های چند باره دیده می شود. به کد زیر توجه کنید:

$data = [
    1 => 1000,
    5 =>  300,
    9 =>  200,
];
$stmt = $pdo->prepare('UPDATE users SET bonus = bonus + ? WHERE id = ?');
foreach ($data as $id => $bonus)
{
    $stmt->execute([$bonus, $id]);
}

من وظیفه ی خود می دانستم که این مورد را توضیح دهم اما در زمان ما نیاز چندانی به چنین قابلیتی نیست چرا که موقعیت های استفاده از آن بسیار کم است و از طرفی تجزیه ی (parse) کوئری در عصر ما بسیار سریع است. همچنین باید توجه داشته باشید که تنها زمانی می توانید از این ویژگی استفاده کنید که emulation mode خاموش باشد.

دستورات SELECT ،INSERT ،UPDATE و DELETE

هیچ موضوع خاص و نکته ی پیچیده ای راجع به این دستورات وجود ندارد. ممکن است در سایت های اینترنتی دیده باشید، به نوعی به این دستورات آب و تاب می دهند که انگار آن ها را در mysqli ندیده ایم!

از آن جایی که این دوره برای افراد مبتدی نیست، بنده سعی می کنم مواردی را که ارزش یادآوری داشته و مربوط به PDO بوده و با mysqli تفاوت دارد، توضیح بدهم.

دقیقا همانطور که در مثال بالا دیدید تنها کاری که باید بکنید این است که یک کوئری را prepare (آماده کردن با placeholder ها) کرده و سپس execute (اجرا) کنید.

برای کوئری های DELETE و SELECT این پروسه تقریبا یکی است. تنها تفاوتی که در مورد این دستور ها باید به یاد داشته باشید این است:

از آن جایی که کوئری های DML1 (یعنی INSERT، UPDATE، DELETE) هیچ داده ای را بر نمی گردانند، شما می توانید از method chaining (دستورات زنجیره ای) استفاده کرده و ()execute را همراه ()prepare صدا بزنید.

1- قبل از ارائه ی مثال توضیحی راجع به DML:

  • DDL: مخفف  Data Definition Language (به معنی زبان تعریف داده) دستورات یا کوئری هایی هستند برای تعریف ساختار داده ها. مثال: CREATE و ALTER و RENAME و DROP و ...
  • DML: مخفف Data Manipulation Language (به معنی زبان دستکاری و تغییر داده ها): دستورات یا کوئری هایی هستند برای تغییر خود داده ها. مثال: SELECT و INSERT و UPDATE و DELETE و...

بر اساس چیزی که گفته شد به مثال زیر توجه کنید:

$sql = "UPDATE users SET name = ? WHERE id = ?";
$pdo->prepare($sql)->execute([$name, $id]);

اما اگر بخواهید تعداد ردیف های تغییر یافته را نیز ببینید باید از همان روال همیشگی استفاده کنید:

$stmt = $pdo->prepare("DELETE FROM goods WHERE category = ?");
$stmt->execute([$cat]);
$deleted = $stmt->rowCount();

دریافت داده ها از طریق ()foreach

ساده ترین و مستقیم ترین روش دریافت ردیف های مختلف داده از یک statement استفاده از حلقه ی ()foreach است. در PHP می توانید با حلقه ی ()foreach روی PDOStatement گردش (iterate) کنید. حتما با iterate (به معنی تکرار یا گردش) آشنا هستید؛

به گردش یک حلقه روی یک شیء، آرایه و .. و پردازش آن، iterate می گوییم، در واقع همان کاری که حلقه ها همیشه می کنند!

به مثال زیر توجه کنید:

$stmt = $pdo->query('SELECT name FROM users');
foreach ($stmt as $row)
{
    echo $row['name'] . "\n";
}

در ذهن خود به یاد داشته باشید که این روش، مشکلی برای حافظه ی (memory) برنامه ی ما ایجاد نمی کند، چرا که به جای بارگذاری (load) تمام ردیف ها به صورت یکجا، آن ها را تک تک و دانه دانه تحویل می دهد.

دریافت داده ها از طریق ()fetch

ما قبلا و در mysqli با این تابع آشنا شده ایم اما بهتر است از نزدیک نگاهی دیگر به آن بیندازیم. نحوه ی کار این تابع به این شکل است:

  • ابتدا یک ردیف از نتایج را برگردانده و pointer خود را در نتیجه ها یک واحد به جلو می برد. قبل از توضیح بقیه ی مراحل باید مبحث pointer را توضیح دهم:

وقتی یک کوئری را اجرا می کنید، (در صورت امکان) آن کوئری به شما یک data set (به معنی یک دسته داده، که همان مجموعه ی نتایج کوئری شماست) بر میگرداند. تصویر زیر را به عنوان یک data set تصور کنید:

pointer همان فلشی است که در ابتدا روی تنیجه ی اول قرار می گیرد، عملیات مناسب را روی آن انجام می دهد و سپس می رود روی نتیجه ی دوم. سپس عملیات مناسب (چیزی که ما تعیین کرده ایم تا روی نتایج انجام شود) را انجام داده و می رود روی نتیجه ی سوم الی آخر ...

  • سپس صدا زدن های مکرر این تابع باعث می شود نتایج یک به یک به ما داده شود.

این روش کار آن را تا حدی شبیه به تابع ()mysql_fetch_array می کند، اما تفاوتی نیز با آن دارد. به جای داشتن توابع متعدد (مثل ()mysql_fetch_assoc و ()mysql_fetch_row) فقط یک تابع داریم که رفتارش با پارامتر های مختلف تغییر می کند. حالت های fetch در PHP زیاد هستند و بعدا در مورد آن ها صحبت خواهیم کرد اما جهت آشنایی اولیه، به صورت خلاصه از آن ها نام می برم:

  • PDO::FETCH_NUM : یک آرایه ی عددی (ایندکس عددی) را بر میگرداند.
  • PDO::FETCH_ASSOC : یک آرایه ی متناظر را بر میگردند.
  • PDO::FETCH_BOTH : هر دو مورد بالا را بر میگرداند.
  • PDO::FETCH_OBJ : یک شیء را بر میگرداند.
  • PDO::FETCH_LAZY : بدون اینکه حافظه ی برنامه مختل و اشغال شود، برای شما استفاده از هر سه مورد (آرایه ی عددی، آرایه ی متناظر و شیء) را ممکن می کند.

از مطالب بالا می توان گفت این متد چه زمانی به کار می رود:

  • زمانی که تنها یک ردیف را می خواهیم. به طور مثال:
$row = $stmt->fetch(PDO::FETCH_ASSOC);

این کد به شما یک ردیف از statement (در اینجا، متغیر stmt$) را به صورت یک آرایه ی متناظر می دهد.

  • زمانی که بخواهیم داده ی برگردانده شده را قبل از استفاده، پردازش کنیم. در چنین حالتی باید در حلقه ی while و ... پردازش شود. مثال استفاده از while:
$stmt = $pdo->query('SELECT name FROM users');
while ($row = $stmt->fetch())
{
    echo $row['name'] . "\n";
}

متد دیگری که به درد بخورد است PDO::FETCH_CLASS نام دارد که می تواند یک شیء از یک کلاس خاص را به ما بدهد:

$news = $pdo->query('SELECT * FROM news')->fetchAll(PDO::FETCH_CLASS, 'News');

این کد یک آرایه به شما می دهد که پر از اشیاء از کلاس News می باشد و خصوصیاتِ (property) کلاس ها را از روی مقادیر برگشت داده شده تعیین می کند.

در این روش به یاد داشته باشید که:

  • خصوصیات قبل از constructor تعیین می شوند.
  • برای تمامی خصوصیاتِ undefined از متد set__ استفاده خواهد شد.
  • اگر هیچ متد set__ در کلاس نباشد، خصوصیت مورد نظر ساخته خواهد شد.

به یاد داشته باشید که حالت پیش فرض این متد PDO::FETCH_BOTH است اما می توانید طبق مثال بالا مثلا با استفاده از PDO::ATTR_DEFAULT_FETCH_MODE آن را تغییر دهید

خلاصه ی مقاله

در این قسمت با انواع روش های دریافت داده ها در PDO مانند حلقه ی foreach و دستور fetch آشنا شدیم؛ سعی کرده ام تا جایی که ممکن است بحث را باز و ریز کنم تا جای شبهه و ابهامی باقی نمانده باشد اما با این حال به یاد داشته باشید که این دوره مخصوص افرادی است که آشنایی قبلی با مباحث پایگاه داده و برنامه نویسی شیء گرا دارند.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش PDO توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (2 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

MhNova
30 خرداد 1399
یک سوال، در نوشتن کویری ها بهتر است از کوتیشن استفاده کنیم، یا دابل کوتیشن ؟؟

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

MhNova
30 خرداد 1399
واقعا عالیییییی

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.