ดักจับข้อผิดพลาดใน PHP ด้วย try...catch

ในที่สุด PHP 5 ก็สามารถดักจับข้อผิดพลาด (Exception handling) เหมือนกับภาษาอื่นๆ ซักที Exception คือสถานการณ์ที่โปรแกรมทำงานพลาด แทนที่จะปล่อยให้โปรแกรมหยุดทำงาน เราสามารถเขียนโปรแกรมดักจับข้อผิดพลาดเพื่อควบคุมโปรแกรมต่ออีกหน่อยว่าโปรแกรมควรจะทำอะไรเวลาเจอข้อผิดพลาดนั้น

วิธีดักจับข้อผิดพลาดแบบเดิมๆ

สมมติให้ average เป็นฟังก์ชันในการคำนวณค่าเฉลี่ย โดยเอา $sum หาร $n ($sum เป็นผลรวมทั้งหมดและ $n เป็นจำนวนข้อมูล) เรารู้ว่าฟังก์ชันนี้จะทำงานผิดพลาดเมื่อ $n เป็น 0 จะไม่สามารถคำนวณค่า $sum/$n ได้ เพราะการหารด้วย 0 ไม่นิยาม เราจึงออกแบบโปรแกรมให้คืนค่า -1 เมื่อไม่สามารถคำนวณค่าได้

<?php
function average($sum, $n)
{
    if($total == 0)
        return -1;   // ฟังก์ชันนี้จะคืนค่า -1 ถ้าไม่สามารถคำนวณค่าเฉลี่ย
    return $sum / $n;
}
 
$avg = average(100, 0);
if($avg == -1)
    echo "ไม่สามารถหาค่าเฉลี่ยได้ เพราะจำนวนข้อมูลเป็น 0";
else {
    echo "Average = ", $avg;
    // do something else here
}
?>

โปรแกรมจะคำนวณได้ตามปกติ และแสดงข้อผิดพลาดได้ตามปกติ… แต่เอ.. มันจะไม่ปกติก็ต่อเมื่อ ผลการคำนวณค่าเฉลี่ย ($sum / $n) มีค่าเป็น -1 ซึ่งซ้ำกับค่าที่เราใช้ในการบอกว่าฟังก์ชันคำนวณค่าเฉลี่ยไม่ได้ เราจะมีวิธีแก้ยังไง?….แอบเฉลยก่อน… ก็ลองใช้ try…catch ดูสิครับ

ดักจับข้อผิดพลาดด้วย try…catch

ดูโค้ดที่แล้ว ลองคิดดูว่า ถ้าโปรแกรมเราต้องเรียก average ซัก 3 ครั้ง เราจะต้องมี if กับ else เพิ่มขึ้นมาอีก 3 อัน แล้วถ้ามันซ้อนๆ กัน โปรแกรมเราจะมี if…else ที่ซ้อนๆ กันอีกเยอะแยะมากมาย เรามาลองดูวิธีดักจับเหมือนเดิม แต่เปลี่ยนมาใช้ try…catch แทน

<?php
function average($sum, $n)
{
    if($total == 0)
        throw new Exception("ไม่สามารถหาค่าเฉลี่ยได้ เพราะจำนวนข้อมูลเป็น 0");    //แก้ไขที่บรรทัดนี้
    return $sum / $n;
}
 
try {
    $avg= average(100, 0);
    echo "Average = ", $avg;
} catch (Exception $e) {
    echo $e->getMessage(), " at line ", $e->getLine();
}
?>

จากโค้ดข้างบนจะเห็นว่า โปรแกรมของเราสะอาดกว่าเดิมขึ้นเยอะ เพราะ ตัวดักจับ error ถูกแยกออกมาอยู่ในส่วน catch อย่างชัดเจน

try, throw, และ catch

try {
    // โค้ดที่อาจทำให้เกิด Exception
    // สามารถเขียนโค้ดปนอยู่กับโปรแกรมปกติได้
} catch (Exception $e) {
    // เมื่อมี Exception (ข้อผิดพลาด) เกิดขึ้นในบรรทัดใดบรรทัดหนึ่งด้านบน
    // โค้ดที่อยู่ในส่วน catch จะถูกเรียกทำงานแทน โดยตัวแปร $e (ตั้งชื่ออื่นก็ได้)
    // มีชนิดเป็น Exception Object จะเก็บค่าว่า Exception เนี่ยเกิดขึ้นที่บรรทัดไหน
    // มีข้อความบอก Error ว่าอย่างไรบ้าง
}

ในส่วนของฟังก์ชันที่เราเรียกหรือโค้ดที่อยู่ใน try จะมีคำสั่ง throw ที่ใช้ในการโยนข้อผิดพลาด…. เอ๋!? โยนทำไมเหรอ?… ก็โยนข้อผิดพลาดมาให้ catch จัดการต่อไปว่าจะทำอะไรดีกับข้อผิดพลาดนั้น นั่นเองครับ ดังนั้นโค้ดบรรทัดต่อๆ ที่อยู่ใต้บรรทัดที่ throw จะไม่ถูกเรียกใช้งาน

คำสั่ง throw จะต้องตามด้วย Exception Object ที่ระบุว่าข้อผิดพลาดที่เกิดขึ้นนั้นคือข้อผิดพลาดอะไร? ลองดูว่า Exception Object ของ PHP มี method, properties อะไรให้เราใช้บ้าง

Exception class

<?php
class Exception
{
    protected $message = 'Unknown exception';   // ข้อความที่บอกว่าข้อผิดพลาดนี้คืออะไร
    protected $code = 0;                        // เราสามารถระบุหมายเลขข้อผิดพลาดเพื่อใช้ในโปรแกรมของเราเองได้
    protected $file;                            // ไฟล์ที่เกิดข้อผิดพลาด (PHP ระบุให้ หรือจะแก้เองก็ได้)
    protected $line;                            // บรรทัดที่เกิดข้อผิดพลาด
 
    function __construct($message = null, $code = 0);   // constructor ของ class นี้
 
    final function getMessage();                // เรียกดู $message (ข้อความที่บอกว่าข้อผิดพลาดนี้คืออะไร)
    final function getCode();                   // เรียกดู $code (หมายเลขของข้อผิดพลาด)
    final function getFile();                   // เรียกดู $file (ไฟล์ที่ throw ข้อผิดพลาดนี้ออกมา)
    final function getLine();                   // เรียกดู $line (บรรทัดที่ก่อให้เกิดข้อผิดพลาด)
    final function getTrace();                  // array ที่เก็บว่ามีการเรียกฟังก์ชันซ้อนๆ กันผ่านฟังก์ชันอะไรบ้าง
    final function getTraceAsString();          // คล้ายกับ getTrace() แต่เป็นข้อมูลที่ถูกจัดรูปแบบให้เป็น string แล้ว
 
    /* Overrideable (สามารถแทนที่ด้วยฟังก์ชันของเราเองได้) */
    function __toString();                       // คำสั่งที่ใช้แสดงผลวัตถุนี้เป็นข้อความ
}
?>

เราสามารถสร้างคลาสใหม่ที่ extend คลาส Exception ที่มีอยู่แล้วได้ เพื่อปรับแต่งให้เหมาะสมกับการใช้งาน ดูตัวอย่างการ extend ได้ที่ PHP: Exceptions - Manual

สรุป

การดักจับข้อผิดพลาด หรือ Exception ต่างๆ สามารถช่วยให้โปรแกรมของเราดูสะอาดขึ้น ไม่มี if ซ้อนกันเยอะๆ ลึกๆ ไม่ต้องใช้คำสั่ง die ทำให้เมื่อเกิดข้อผิดพลาด โปรแกรมก็ยังสามารถทำงานต่อไปได้ และยังสามารถแจ้งผู้ใช้ให้ทราบถึงข้อผิดพลาดนั้นได้อย่างเป็นมิตรกับผู้ใช้ (user-friendly)

ขอบคุณมากครับ กำลังหาอยู่ ไม่นึกว่าจะเจอจากเว็บไทย

ขอบคุณครับ

ขอบคุณครับ.............
แปล Text-Book อยู่ตั้งนาน

Post new comment

คำนวณผลบวกด้านบนแล้วกรอกผลลัพธ์ลงในช่อง เช่น 2 ลบ 1 ให้พิมพ์ 1