การสร้าง Custom Exception
ในโลกของการพัฒนา API การจัดการข้อผิดพลาด (Error Handling) เป็นสิ่งสำคัญอย่างยิ่ง เพราะ API ที่ดีต้องสามารถแจ้งให้ผู้ใช้งานทราบได้ว่าเกิดอะไรขึ้นเมื่อมีปัญหา และต้องให้ข้อมูลที่เพียงพอต่อการแก้ไขปัญหาเหล่านั้น การใช้ Exception เป็นวิธีที่นิยมในการจัดการข้อผิดพลาดใน PHP แต่บางครั้ง Exception ที่มีอยู่ (เช่น Exception, InvalidArgumentException) อาจไม่เพียงพอที่จะสื่อถึงปัญหาที่เกิดขึ้นในบริบทของ API ของเรา การสร้าง Custom Exception จึงเป็นทางเลือกที่ดีกว่า เพราะช่วยให้เราสามารถกำหนดชนิดของข้อผิดพลาดได้อย่างละเอียดและจัดการกับมันได้อย่างเหมาะสม
Custom Exception คืออะไร
Custom Exception คือ Class ที่เราสร้างขึ้นเองโดยสืบทอด (Inherit) จาก Class Exception หรือ Class อื่นๆ ที่เป็น Exception อยู่แล้ว (เช่น RuntimeException, LogicException) การทำเช่นนี้ทำให้ Custom Exception ของเรามีคุณสมบัติพื้นฐานของ Exception ทั่วไป (เช่น message, code, file, line) แต่เราสามารถเพิ่มคุณสมบัติและเมธอดเฉพาะเจาะจงที่เกี่ยวข้องกับปัญหาที่ต้องการจัดการได้
เหตุผลที่ควรใช้ Custom Exception:
- ความชัดเจน: ช่วยให้โค้ดอ่านง่ายและเข้าใจง่ายขึ้น เพราะชื่อของ Exception จะสื่อถึงปัญหาที่เกิดขึ้นอย่างชัดเจน
- การจัดการข้อผิดพลาดที่เฉพาะเจาะจง: ช่วยให้เราสามารถเขียน
catchblock ที่จัดการกับ Exception ประเภทนั้นๆ ได้โดยเฉพาะ ทำให้การจัดการข้อผิดพลาดมีความละเอียดและแม่นยำมากขึ้น - การแยก Concern: ช่วยแยก Concern ของการจัดการข้อผิดพลาดออกจาก Logic หลักของโปรแกรม ทำให้โค้ดมีความ Modular และ Maintainable มากขึ้น
การสร้าง Custom Exception
การสร้าง Custom Exception ใน PHP ทำได้ง่ายมาก เพียงแค่สร้าง Class ใหม่และสืบทอดจาก Class Exception ตัวอย่างเช่น หากเราต้องการสร้าง Exception สำหรับกรณีที่ API Key ไม่ถูกต้อง เราสามารถทำได้ดังนี้:
<?php
class InvalidApiKeyException extends Exception
{
protected $message = 'Invalid API Key provided.';
protected $code = 401; // HTTP Status Code: Unauthorized
public function __construct($message = null, $code = null, Throwable $previous = null)
{
if ($message !== null) {
$this->message = $message;
}
if ($code !== null) {
$this->code = $code;
}
parent::__construct($this->message, $this->code, $previous);
}
}
คำอธิบาย Code:
class InvalidApiKeyException extends Exception: ประกาศ ClassInvalidApiKeyExceptionซึ่งสืบทอดจาก ClassExceptionprotected $message = 'Invalid API Key provided.';: กำหนดข้อความ Default สำหรับ Exception นี้protected $code = 401;: กำหนด HTTP Status Code ที่เหมาะสมสำหรับ Exception นี้ (Unauthorized)__construct(): Constructor ของ Class ที่สามารถรับข้อความและ Code ที่กำหนดเองได้ หากไม่มีการส่งค่าเข้ามา จะใช้ค่า Default ที่กำหนดไว้parent::__construct($this->message, $this->code, $previous);: เรียก Constructor ของ Class แม่ (Exception) เพื่อกำหนดค่า message, code และ Throwable (Exception ก่อนหน้า)
Trade-offs: การกำหนด $message และ $code เป็น protected ทำให้ Class ลูกสามารถเข้าถึงและแก้ไขค่าเหล่านี้ได้ แต่ Class ภายนอกไม่สามารถเข้าถึงได้โดยตรง ซึ่งเป็นแนวทางปฏิบัติที่ดีในการ Encapsulation
เราสามารถสร้าง Custom Exception อื่นๆ ได้ในลักษณะเดียวกัน เช่น:
<?php
class ResourceNotFoundException extends Exception
{
protected $message = 'Resource not found.';
protected $code = 404; // HTTP Status Code: Not Found
}
class DatabaseConnectionException extends Exception
{
protected $message = 'Failed to connect to the database.';
protected $code = 500; // HTTP Status Code: Internal Server Error
}
การใช้งาน Custom Exception
เมื่อเราสร้าง Custom Exception แล้ว เราสามารถใช้มันใน Code ของเราได้โดยการ throw Exception นั้นๆ เมื่อเกิดข้อผิดพลาดที่เกี่ยวข้อง ตัวอย่างเช่น:
<?php
function validateApiKey(string $apiKey): bool
{
// สมมติว่ามีการตรวจสอบ API Key ในฐานข้อมูล
if ($apiKey !== 'valid_api_key') {
throw new InvalidApiKeyException();
}
return true;
}
try {
$apiKey = $_GET['api_key'] ?? '';
validateApiKey($apiKey);
// Logic ของ API ที่นี่
echo "API Key is valid. Processing request...\n";
} catch (InvalidApiKeyException $e) {
// ส่ง JSON Response กลับไปพร้อม Error Message และ HTTP Status Code
http_response_code($e->getCode());
header('Content-Type: application/json');
echo json_encode([
'error' => $e->getMessage(),
'code' => $e->getCode()
]);
exit;
} catch (Exception $e) {
// จัดการ Exception อื่นๆ ที่อาจเกิดขึ้น
http_response_code(500);
header('Content-Type: application/json');
echo json_encode([
'error' => 'Internal Server Error',
'message' => $e->getMessage(),
'code' => 500
]);
exit;
}
คำอธิบาย Code:
validateApiKey(): Function ที่ตรวจสอบ API Key และthrowInvalidApiKeyExceptionหาก API Key ไม่ถูกต้องtry...catch: Block ที่ใช้ดักจับ Exception ที่อาจเกิดขึ้นcatch (InvalidApiKeyException $e): Block ที่จะทำงานเมื่อInvalidApiKeyExceptionถูกthrowhttp_response_code($e->getCode());: กำหนด HTTP Status Code ตาม Code ที่กำหนดไว้ใน Exceptionjson_encode(): สร้าง JSON Response ที่มี Error Message และ Code
แนวปฏิบัติที่ดี:
- ระบุ HTTP Status Code ที่ถูกต้อง: การกำหนด HTTP Status Code ที่ถูกต้องใน Custom Exception จะช่วยให้ Client เข้าใจถึงประเภทของข้อผิดพลาดที่เกิดขึ้นได้ง่ายขึ้น
- ให้ข้อมูลที่เพียงพอ: Error Message ควรให้ข้อมูลที่เพียงพอต่อการแก้ไขปัญหา แต่ไม่ควรเปิดเผยข้อมูลที่ละเอียดอ่อน
- Logging: ควร Log Exception ที่เกิดขึ้น เพื่อใช้ในการ Debug และ Monitor API
- Catch Exception ที่เฉพาะเจาะจง: พยายาม Catch Exception ที่เฉพาะเจาะจงเท่าที่จะเป็นไปได้ เพื่อให้การจัดการข้อผิดพลาดมีความแม่นยำมากขึ้น
การสร้าง Custom Exception เป็นเครื่องมือที่มีประโยชน์อย่างมากในการจัดการข้อผิดพลาดใน API ช่วยให้เราสามารถกำหนดชนิดของข้อผิดพลาดได้อย่างละเอียดและจัดการกับมันได้อย่างเหมาะสม ทำให้ API ของเรามีความแข็งแกร่งและเชื่อถือได้มากยิ่งขึ้น