آشنایی با نحوهٔ مدیریت اِکسپشن‌ها در زبان PHP


Exception در لغت به معنای «استثناء» است اما در زبان‌های برنامه‌نویسی از یک دید کلی می‌توان آن‌ها را همچون ارورها تلقی کرد به طوری که وقتی ایجاد می‌شوند، ادامهٔ‌ روند اجرای برنامه متوقف می‌گردد. از نسخهٔ PHP 5.0 به بعد قابلیتی به این زبان اضافه شد که از آن طریق توسعه‌دهندگان این زبان می‌توانند یک اِکسپشن را به اصطلاح Throw سپس Catch کنند. به بیانی قابل‌فهم‌تر، این قابلیت در زبان پی‌اچ‌پی گنجانده شده تا بر اساس الگوریتم مد نظر توسعه‌دهنده، وی بتوانند در صورت نیاز و در شرایطی خاص Throw Exception کند؛ یعنی یک اِکسپشن ایجاد کرده و پیامی داخل آن درج نموده و دلیل وقوع آن را توضیح دهد سپس در جایی دیگر از کد Catch Exception کند بدان معنا که اِکسپشن را دریافت نموده و پیامش را در معرض دید کاربر قرار دهد.

در حقیقت، اِکسپشن‌ها این امکان را در اختیارمان قرار می‌دهند تا بتوانیم در صورتی که چیزی به خطا رفت، به سادگی جریان اجرای برنامه را متوقف نموده و یا برنامه را ادامه داده اما پیامی در معرض دید کاربر قرار داد مضاف بر این که از طریق اِکسپشن‌ها می‌توانیم نحوهٔ هندل کردن ارورها را به هر شکلی که بخواهیم مدیریت کنیم. اساساً وقتی که اِکسپشنی رخ می‌دهد، روند اجرای برنامه متوقف می‌گردد مگر آن که به شیوه‌ای کدنویسی کرده باشیم که آن اِکسپشن به اصطلاح Catch گردد.

هشدار
اِکسپشن‌های مدیریت نشده‌ای که وقتی نرم‌افزار روی سرورهای اصلی دیپلوی شد رخ می‌دهند، منجر به توقف کامل نرم‌افزار شده و بالتبع تجربهٔ‌ کاربری بدی را برای کاربران رقم خواهند زد.

اِکسپشن‌ها بخشی از OOP در زبان پی‌اچ‌پی هستند به طوری که بر آن اساس می‌توان از کلاس‌های مخصوص این کار که در هستهٔ این زبان گنجانده شده ارث‌بری نموده و کلاس‌های کاستومایزشده‌ای برای هندل کرد ارورها ساخت.

آشنایی با کلاس Exception

در زبان پی‌اچ‌‌پی یک کلاس پایه‌ای داریم تحت عنوان Exception که به منظور مدیریت اِکسپشن‌ها مورد استفاده قرار می‌گیرد. به منظور درک بهتر سازوکار این کلاس، داخل پوشهٔ oop پروژه‌ای تحت عنوان exception-handling ساخته و ساختار پروژه‌ای که در این دورهٔ آموزشی از ابتدا مورد استفاده قرار دادیم را داخل آن ایجاد می‌کنیم. برای شروع، داخل پوشهٔ classes فایلی به نام User.php ساخته و آن را به صورت زیر تکمیل می‌کنیم:

<?php
namespace SokanAcademy;

class User
{
    public function isDeveloper(bool $value)
    {
        if ($value == true) {
            return "This user is a developer.";
        } else {
            throw new Exception("EXCEPTION: This user is not a developer.");
        }
    }
}

داخل این کلاس متدی نوشته‌ایم به نام ()isDeveloper که اساساً چک می‌کند ببیند که آیا آبجکت ساخته‌شده از روی این کلاس یک توسعه‌دهنده است یا خیر. این متد یک پارامتر ورودی می‌گیرد تحت عنوان value$ که تایپ هینت آن bool است بدان معنا که آرگومان‌های انتخابی برای این متد فقط و فقط می‌توانند true یا false باشند. داخل بدنهٔ این متد با استفاده از یک دستور شرطی چک کرده‌ایم ببینیم که آیا مقدار پارامتر ورودی برابر با true است یا خیر که اگر این گونه بود، وارد بلوک if شده و استرینگی مبنی بر این که آبجکت ساخته‌شده از روی این کلاس یک دولوپر است ریترن می‌کنیم و در غیر این صورت نیز وارد بلوک else شده و با استفاده از کیورد throw آبجکتی از روی کلاس Exception پی‌اچ‌پی ساخته و استرینگی را به عنوان پارامتر ورودی این کلاس در نظر می‌گیریم. حال وارد فایل index.php شده و آن را به صورت زیر تکمیل می‌کنیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$user = new SokanAcademy\User();
echo $user->isDeveloper(false);
echo "\n";
echo "The rest of the program.";

همان‌طور که می‌بینیم، از روی کلاس User آبجکتی ساخته‌ایم به نام user$ سپس در خط بعد متد ()isDeveloper را به آن منتسب نموده و نتیجه را چاپ کرده‌ایم به طوری که اگر این فایل را در محیط کامندلاین اجرا کنیم، به عنوان خروجی خواهیم داشت:

/var/www/oop/exception-handling$ php index.php 
PHP Fatal error:  Uncaught Error: Class 'SokanAcademy\Exception' not found in /var/www/oop/exception-handling/classes/User.php:11

اساساً وقوع این ارور خارج از نکات آموزشی موضوع مورد بحث در این آموزش است و می‌توان گفت صرفاً به دلیل بی‌دقتی در توسعهٔ کلاس User رخ داده است! به عبارتی، متن این ارور حاکی از آن است که کلاسی تحت عنوان Exception داخل کلاس User به رسمیت شناخته نشده است. 

پیش از این توضیح دادیم که وقتی از نِیم‌اِسپیس استفاده می‌کنیم، کلاس‌هایی که در هستهٔ زبان پی‌اچ‌پی تعبیه شده‌اند را می‌باید با درج علامت \ مورد استفاده قرار دهیم که در غیر این صورت،‌ با ارور مواجه خواهیم شد و درج این علامت موجب می‌گردد که مفسر پی‌اچ‌پی نِیم‌اِسپیسی که داخلش قرار داریم را نادیده بگیرد. برای همین منظور، کلاس User را به صورت زیر اصلاح می‌کنیم:

<?php
namespace SokanAcademy;

class User
{
    public function isDeveloper(bool $value)
    {
        if ($value == true) {
            return "This user is a developer.";
        } else {
            throw new \Exception("EXCEPTION: This user is not a developer.");
        }
    }
}

حال مجدد فایل index.php را اجرا می‌کنیم:

/var/www/oop/exception-handling$ php index.php 
PHP Fatal error:  Uncaught Exception: This user is not a developer. in /var/www/oop/exception-handling/classes/User.php:11

می‌بینیم که مجدد به ارور برخوردیم اما این بار ارور فوق همانی است که خودمان دست به ایجادش زده‌ایم و اگر به متن ارور توجه کنیم،‌ می‌بینیم که دقیقاً همان استرینگی که به عنوان آرگومان ورودی کلاس Exception در نظر گرفته‌ بودیم چاپ شده است با این توضیح که در متن ارور چیزی تحت عنوان «Uncaught Exception» نیز چاپ شده است بدان معنا که ارور یا اِکسپشن فوق Catch یا Handle و یا بهتر بگوییم مدیریت نشده است. نکته‌ای که در ارتباط با اجرای کد فوق وجود دارد آن است که متنی که در خط هشتم نوشته‌‌ایم هرگز چاپ نشده است زیرا پیش از این گفتیم وقتی که اِکسپشنی رخ می‌‌دهد، اگر آن را هندل نکنیم روند اجرای برنامه متوقف شده و از آن نقطه‌ای که اِکسپشن رخ داده به بعد دیگر اجرا نخواهد شد و همین مسئله لزوم هندل کردن اِکسپشن‌ها را نشان می‌دهد.

در زبان برنامه‌نویسی پی‌اچ‌پی کلیدواژگانی داریم تحت عنوان try و catch که به منظور مدیریت اِکسپشن‌ها مورد استفاده قرار می‌گیرند که برای روشن‌تر شدن نحوهٔ کارکرد آن‌ها، فایل index.php را به صورت زیر تکمیل می‌کنیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$user = new SokanAcademy\User();
try {
    echo $user->isDeveloper(true);
} catch(Exception $e) {
    echo $e->getMessage();
}
echo "\n";
echo "The rest of the program.";

ابتدا خروجی کدهای فوق را مشاهده نموده سپس به تفسیر آن‌ها خواهیم پرداخت:

/var/www/oop/exception-handling$ php index.php 
This user is a developer.
The rest of the program.

با توجه به این که آرگومان true را برای متد ()isDeveloper در نظر گرفته‌ایم، صرفاً کدهای داخل بلوک if این متد اجرا شده و هیچ گونه اِکسپشنی ایجاد نخواهد شد و می‌بینیم که استرینگ مرتبط با خط دوازدهم (خط هشتم در نمونهٔ قبل) به درستی چاپ شده است.

در توضیح کدهای فوق می‌توان گفت آن بخشی از کد که قصد داریم اجرایش کنیم را داخل بلوک try قرار داده‌ایم که این وظیفه را دارا است تا طبق روال معمول کدها را اجرا کند. اگر کد مشکلی نداشته باشد و اساساً‌ هیچ گونه اِکسپشنی رخ ندهد، پس از اِتمام اجرای کدهای داخل این بلوک، از ساختار try و catch خارج شده و ادامهٔ کدها شروع به اجرا می‌کنند و همان‌طور که می‌بینیم، خط دوازدهم هم اجرا شده است اما اگر در حین توسعهٔ متد ()isDeveloper یک اِکسپشن‌ به اصطلاح Throw کرده باشیم، بلافاصله وارد بلوک catch خواهیم شد به طوری که برای تست این موضوع، کدهای داخل فایل index.php را به صورت زیر تغییر می‌دهیم:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$user = new SokanAcademy\User();
try {
    echo $user->isDeveloper(false);
} catch (Exception $e) {
    echo $e->getMessage();
}
echo "\n";
echo "The rest of the program.";

تنها کاری که انجام داده‌ایم آن است که برای متد ()isDeveloper به جای آرگومان true از false استفاده نموده‌ایم و از این پس در خروجی خواهیم داشت:

/var/www/oop/exception-handling$ php index.php 
EXCEPTION: This user is not a developer.
The rest of the program.

همان‌طور که می‌بینیم، به دلیل این که از مقدار false استفاده کرده‌ایم، داخل متد ()isDeveloper دستور داده‌ایم تا وارد بلوک else شده و در آنجا هم یک اِکسپشن ایجاد کرده‌ایم و سازوکار ساختار try و catch بدین شکل است که اگر در خروجی متد مذکور اِکسپشن ایجاد شده باشد، وارد بلوک catch خواهد شد. همان‌طور که ملاحظه می‌شود، داخل پرانتزهای مرتبط با catch آبجکتی تحت عنوان e$ یا هر نام دلخواه دیگری از روی کلاس Exception ساخته‌ایم و این کلاس متدی دارد تحت عنوان ()getMessage که حاوی پیام‌های مرتبط با اِکسپشن‌ها است و داخل بلوک catch هم خروجی این متد را چاپ کرده‌ایم و از آنجا که قبلاً داخل کلاس User پیامی همچون «.EXCEPTION: This user is not a developer» برای آبجکت ساخته‌شده از روی کلاس Exception در نظر گرفته‌ایم، مسلماً داخل بلوک catch به آن دسترسی خواهیم داشت.

آنچه در ارتباط با کدهای فوق قابل‌تأمل است این که می‌بینیم وقوع اِکسپشن‌ هرگز منجر به توقف برنامه نشده و نه تنها تجربهٔ‌ کاربری بدی برای کاربر رقم نخواهد خورد، بلکه اگر متن ارور گویا باشد وی خواهد دانست که در گام بعدی چه کاری باید انجام دهد.

علاوه بر متد ()getMessage یک سری متد دیگر داخل کلاس Exception برای مصارف مختلف گنجانده شده‌اند که عبارتند از:

final public getMessage (void) : string
final public getPrevious (void) : Throwable
final public getCode (void) : mixed
final public getFile (void) : string
final public getLine (void) : int
final public getTrace (void) : array
final public getTraceAsString (void) : string

طور مثال، از متد ()getFile به صورت زیر می‌توان استفاده نمود تا آدرس فایلی که اِکسپشن در آن درخ داده است را نشان داد:

<?php
ini_set('display_errors', '1');
require_once 'vendor/autoload.php';

$user = new SokanAcademy\User();
try {
    echo $user->isDeveloper(false);
} catch (Exception $e) {
    echo $e->getFile();
}
echo "\n";
echo "The rest of the program.";

به عنوان خروجی هم خواهیم داشت:

/var/www/oop/exception-handling/classes/User.php
The rest of the program.

می‌بینیم که خروجی متد ()getFile یک استرینگ است حاوی آدرس فایلی که اِکسپشن مذکور داخل آن رخ داده است (اگر متد ()getLine را فراخوانی کنیم، می‌بینیم که به درستی خروجی ۱۱ را نشان می‌دهد که مرتبط با خط یازدهمی داخل فایل User.php است که اِکسپشن فوق رخ داده است.)

اساساً Exception Handling یکی از بخش‌های لاینفک شیئ‌گرایی در زبان پی‌اچ‌پی است به طوری که با ارث‌بری از کلاس پایهٔ Exception می‌توان برای بخش‌های مختلف نرم‌افزار اِکسپشن‌های کاستومایزشده‌ای نوشته و در موقعیت مناسب از آن‌ها استفاده نمود که در ادامهٔ این آموزش به بررسی دقیق‌تر این موضوع خواهیم پرداخت.

این بخش از محتوا مخصوص کاربرانی است که ثبت‌نام کرده‌اند.
جهت مشاهدهٔ این بخش از محتوا لاگین نمایید.

جمع‌بندی
زمانی که پای توسعهٔ نرم‌افزار به میان می‌آید، یکی از بخش‌های لاینفک این پروسه ایجاد سهوی باگ‌هایی است که در نهایت منجر به بروز یک سری ارور یا اِکسپشن می‌شوند و ما به عنوان برنامه‌نویس وظیفه داریم که تا حد ممکن آن‌ها را به بهترین شکل مدیریت کنیم. در همین راستا، در این آموزش به بررسی کلاس Exception زبان برنامه‌نویسی پی‌اچ‌پی پرداخته و در ادامه دیدیم که به چه شکل می‌توان بسته به نیازهای نرم‌افزاری خود اقدام به ساخت کلاس‌های مدیریت اِکسپشن شخصی‌سازی‌شده‌ای پرداخت.

دانلود فایل‌های تمرین

لیست نظرات
کاربر میهمان
دیدگاه شما چیست؟
کاربر میهمان