Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

การจัดการ Exception ที่ไม่ได้ถูก Catch

บทความนี้กล่าวถึงความสำคัญของการจัดการ Exception ที่ไม่ได้ถูก `catch` ใน PHP เพื่อป้องกันการหยุดทำงานของโปรแกรมอย่างกะทันหันและให้ข้อมูลที่เป็นประโยชน์เมื่อเกิด...

การจัดการ Exception ที่ไม่ได้ถูก Catch

ในบทที่แล้ว เราได้เรียนรู้วิธีการเข้าถึงค่า Environment Variables ที่โหลดมาจากไฟล์ .env ในบทนี้ เราจะมาพูดถึงการจัดการ Exception ที่ไม่ได้ถูก catch หรือถูกจับ เพื่อให้แอปพลิเคชันของเราทำงานได้อย่างราบรื่นและสามารถให้ข้อมูลที่เป็นประโยชน์เมื่อเกิดข้อผิดพลาดที่ไม่คาดคิด

Global Exception Handler คืออะไร?

โดยปกติแล้ว เมื่อเกิด Exception ใน PHP ถ้าเราไม่ได้ใช้ try-catch เพื่อดักจับ Exception นั้น โปรแกรมจะหยุดทำงานทันที และแสดงข้อผิดพลาด (error) ออกมา ซึ่งอาจจะไม่เป็นมิตรกับผู้ใช้งาน และไม่ช่วยให้เราเข้าใจถึงปัญหาที่เกิดขึ้น ดังนั้น เราจึงจำเป็นต้องมีวิธีในการจัดการ Exception ที่ไม่ได้ถูก catch เพื่อให้:

  • บันทึกข้อมูลของ Exception เพื่อนำไปวิเคราะห์และแก้ไข
  • แสดงข้อความที่เป็นมิตรต่อผู้ใช้งาน แทนที่จะเป็นข้อความ error ที่ซับซ้อน
  • ป้องกันไม่ให้โปรแกรมหยุดทำงานอย่างกะทันหัน

PHP มีฟังก์ชัน set_exception_handler() ที่ช่วยให้เราสามารถกำหนดฟังก์ชันที่จะถูกเรียกใช้งานเมื่อเกิด Exception ที่ไม่ได้ถูก catch ได้

การใช้งาน set_exception_handler()

set_exception_handler() รับพารามิเตอร์เป็นชื่อของฟังก์ชัน (หรือ closure) ที่จะถูกเรียกใช้งานเมื่อเกิด Exception ที่ไม่ได้ถูก catch

<?php

function handleUncaughtException(Throwable $exception) {
  // บันทึกข้อมูลของ Exception
  error_log("Uncaught Exception: " . $exception->getMessage() . " in " . $exception->getFile() . ":" . $exception->getLine());

  // แสดงข้อความที่เป็นมิตรต่อผู้ใช้งาน
  echo "<h1>ขออภัย เกิดข้อผิดพลาดขึ้น</h1>";
  echo "<p>โปรดลองใหม่อีกครั้ง หรือติดต่อผู้ดูแลระบบ</p>";

  // หยุดการทำงานของสคริปต์ (ป้องกันการทำงานต่อที่อาจทำให้เกิดปัญหา)
  exit;
}

set_exception_handler('handleUncaughtException');

// ตัวอย่างการใช้งาน
throw new Exception("Something went wrong!");

?>

ในตัวอย่างข้างต้น เราได้สร้างฟังก์ชัน handleUncaughtException() ที่รับพารามิเตอร์เป็น Throwable ซึ่งเป็น interface ที่ Exception ทั้งหมด implement ฟังก์ชันนี้จะ:

  1. บันทึกข้อมูลของ Exception โดยใช้ error_log() ซึ่งจะบันทึกข้อมูลไปยังไฟล์ error log ของ PHP (ตำแหน่งของไฟล์ error log จะขึ้นอยู่กับการตั้งค่าของ PHP)
  2. แสดงข้อความที่เป็นมิตรต่อผู้ใช้งาน โดยใช้ HTML
  3. หยุดการทำงานของสคริปต์ โดยใช้ exit เพื่อป้องกันไม่ให้โปรแกรมทำงานต่อ ซึ่งอาจจะทำให้เกิดปัญหาเพิ่มเติม

จากนั้นเราได้เรียกใช้ set_exception_handler('handleUncaughtException') เพื่อกำหนดให้ฟังก์ชัน handleUncaughtException() เป็น Global Exception Handler

เมื่อเรา throw Exception ขึ้นมา (throw new Exception("Something went wrong!")) แต่ไม่มี try-catch ดักจับ Exception นั้น ฟังก์ชัน handleUncaughtException() จะถูกเรียกใช้งาน

การบันทึก Log

ในตัวอย่างข้างต้น เราใช้ error_log() เพื่อบันทึกข้อมูลของ Exception แต่ในบทก่อนๆ เราได้เรียนรู้การใช้งาน Monolog ซึ่งเป็น logging library ที่มีประสิทธิภาพมากกว่า ดังนั้น เราสามารถใช้ Monolog ใน Global Exception Handler ได้

<?php

require __DIR__ . '/vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// สร้าง Logger
$log = new Logger('app');
$log->pushHandler(new StreamHandler(__DIR__ . '/logs/error.log', Logger::ERROR));

function handleUncaughtException(Throwable $exception) {
  global $log; // เข้าถึงตัวแปร $log ที่อยู่ภายนอก scope

  // บันทึกข้อมูลของ Exception โดยใช้ Monolog
  $log->error("Uncaught Exception", [
    'message' => $exception->getMessage(),
    'file' => $exception->getFile(),
    'line' => $exception->getLine(),
    'trace' => $exception->getTraceAsString(),
  ]);

  // แสดงข้อความที่เป็นมิตรต่อผู้ใช้งาน
  echo "<h1>ขออภัย เกิดข้อผิดพลาดขึ้น</h1>";
  echo "<p>โปรดลองใหม่อีกครั้ง หรือติดต่อผู้ดูแลระบบ</p>";

  // หยุดการทำงานของสคริปต์ (ป้องกันการทำงานต่อที่อาจทำให้เกิดปัญหา)
  exit;
}

set_exception_handler('handleUncaughtException');

// ตัวอย่างการใช้งาน
throw new Exception("Something went wrong!");

?>

ในตัวอย่างนี้ เราได้:

  1. Include autoload.php เพื่อให้สามารถใช้งาน Monolog ได้
  2. สร้าง Logger โดยใช้ Monolog และกำหนดให้บันทึกข้อมูลไปยังไฟล์ logs/error.log
  3. แก้ไขฟังก์ชัน handleUncaughtException() ให้ใช้ Monolog ในการบันทึกข้อมูลของ Exception โดยเพิ่มข้อมูลเพิ่มเติม เช่น stack trace
  4. เพิ่ม global $log; ในฟังก์ชัน handleUncaughtException() เพื่อให้สามารถเข้าถึงตัวแปร $log ที่สร้างไว้ภายนอก scope ของฟังก์ชันได้

การใช้ Monolog ทำให้เราสามารถบันทึกข้อมูลของ Exception ได้อย่างละเอียด และสามารถกำหนดรูปแบบการบันทึก (formatter) และตำแหน่งที่จะบันทึก (handler) ได้อย่างยืดหยุ่น

การแสดงผลที่เป็นมิตร

การแสดงข้อความ error ที่ซับซ้อนให้ผู้ใช้งานเห็น อาจทำให้ผู้ใช้งานสับสนและไม่เข้าใจถึงปัญหาที่เกิดขึ้น ดังนั้น เราควรแสดงข้อความที่เป็นมิตรและเข้าใจง่าย เช่น "ขออภัย เกิดข้อผิดพลาดขึ้น โปรดลองใหม่อีกครั้ง หรือติดต่อผู้ดูแลระบบ"

นอกจากนี้ เรายังสามารถแสดงข้อมูลเพิ่มเติมที่เป็นประโยชน์ต่อผู้ใช้งานได้ เช่น:

  • หมายเลขอ้างอิง (reference number) ที่ผู้ใช้งานสามารถนำไปแจ้งกับผู้ดูแลระบบได้
  • ลิงก์ไปยังหน้าช่วยเหลือ หรือหน้า FAQ

แต่ควรระมัดระวังในการแสดงข้อมูลที่ละเอียดเกินไป เช่น stack trace เพราะอาจจะเปิดเผยข้อมูลที่เป็นความลับของระบบ

ข้อผิดพลาดที่พบบ่อย

  • ลืม include autoload.php: ถ้าเราใช้ Composer และ logging library (เช่น Monolog) เราต้อง include autoload.php เพื่อให้ PHP รู้จัก class ที่เราใช้
  • ไม่ได้กำหนด Handler: ถ้าเราไม่ได้กำหนด Handler ใน Monolog ข้อมูล log จะไม่ถูกบันทึกที่ไหนเลย
  • Scope ของตัวแปร: ถ้าเราต้องการเข้าถึงตัวแปรที่สร้างไว้ภายนอก scope ของฟังก์ชัน เราต้องใช้ keyword global
  • การแสดงข้อมูลที่ละเอียดเกินไป: ควรระมัดระวังในการแสดงข้อมูลที่ละเอียดเกินไป เพราะอาจจะเปิดเผยข้อมูลที่เป็นความลับของระบบ

สรุป

การจัดการ Exception ที่ไม่ได้ถูก catch เป็นสิ่งสำคัญในการพัฒนาแอปพลิเคชัน PHP เพื่อให้แอปพลิเคชันทำงานได้อย่างราบรื่นและสามารถให้ข้อมูลที่เป็นประโยชน์เมื่อเกิดข้อผิดพลาดที่ไม่คาดคิด เราสามารถใช้ set_exception_handler() เพื่อกำหนด Global Exception Handler และใช้ logging library (เช่น Monolog) เพื่อบันทึกข้อมูลของ Exception

ในบทถัดไป เราจะพูดถึงการจัดการ Error ที่ไม่ได้ถูก Handle ซึ่งเป็นอีกหนึ่งสิ่งที่สำคัญในการพัฒนาแอปพลิเคชัน PHP

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service