Menu
CoddyTech

Hệ thống phân cấp ngoại lệ tùy chỉnh

Thuộc phần Lập trình hướng đối tượng trong hành trình PHP của Coddy. Bài học 67 trên 91.

Dù các lớp ngoại lệ tích hợp sẵn của PHP xử lý những tình huống phổ biến, ứng dụng thực tế thường cần các loại lỗi cụ thể hơn. Tạo một cấu trúc phân cấp ngoại lệ tùy chỉnh giúp bạn định nghĩa các ngoại lệ phù hợp với lĩnh vực của mình và bắt chúng ở nhiều mức độ cụ thể khác nhau.

Để tạo ngoại lệ tùy chỉnh, bạn chỉ cần mở rộng lớp Exception hoặc một lớp con của nó:

<?php
class PaymentException extends Exception {}

class InsufficientFundsException extends PaymentException {
    public function __construct(
        private float $required,
        private float $available
    ) {
        parent::__construct("Need $required but only $available available");
    }
    
    public function getShortfall(): float {
        return $this->required - $this->available;
    }
}

Lưu ý rằng InsufficientFundsException kế thừa PaymentException, chứ không kế thừa trực tiếp Exception. Điều này tạo ra một hệ thống phân cấp, giúp bạn bắt tất cả ngoại lệ liên quan đến thanh toán bằng một khối catch hoặc xử lý riêng từng ngoại lệ cụ thể.

Ngoại lệ tùy chỉnh có thể có thêm thuộc tính và phương thức liên quan đến lỗi. Ở đây, getShortfall() cung cấp thông tin hữu ích mà ngoại lệ chung không thể cung cấp:

<?php
class Wallet {
    public function __construct(private float $balance) {}
    
    public function pay(float $amount): void {
        if ($amount > $this->balance) {
            throw new InsufficientFundsException($amount, $this->balance);
        }
        $this->balance -= $amount;
    }
}

Hệ thống phân cấp ngoại lệ được thiết kế tốt giúp bạn dễ bảo trì code hơn. Khi bắt ngoại lệ, bạn có thể chọn phạm vi bắt rộng hoặc cụ thể tùy nhu cầu, đồng thời bản thân các đối tượng ngoại lệ chứa thông tin hữu ích về sự cố đã xảy ra.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống xử lý đơn hàng với hệ thống phân cấp ngoại lệ tùy chỉnh để xử lý các loại lỗi đơn hàng khác nhau. Bạn sẽ tạo các ngoại lệ mang theo thông tin hữu ích về sự cố, giúp xử lý lỗi chính xác và đầy đủ hơn.

Bạn sẽ sắp xếp code trong bốn tệp:

  • OrderException.php: Tạo lớp cơ sở OrderException kế thừa từ Exception. Lớp này làm lớp cha cho mọi ngoại lệ liên quan đến đơn hàng, giúp bạn có thể bắt mọi vấn đề về đơn hàng bằng một khối catch duy nhất khi cần.
  • OutOfStockException.php: Tạo lớp OutOfStockException kế thừa từ OrderException. Ngoại lệ này nhận tên sản phẩm và số lượng được yêu cầu trong hàm khởi tạo. Dùng tính năng khai báo thuộc tính trong hàm khởi tạo cho các thuộc tính private này. Gọi hàm khởi tạo của lớp cha với thông báo theo định dạng "[productName] is out of stock (requested: [quantity])". Thêm phương thức getProductName(): string để trả về tên sản phẩm.
  • InvalidQuantityException.php: Tạo lớp InvalidQuantityException kế thừa từ OrderException. Ngoại lệ này nhận một giá trị số lượng trong hàm khởi tạo, dùng tính năng khai báo thuộc tính trong hàm khởi tạo để tạo thuộc tính private. Gọi hàm khởi tạo của lớp cha với thông báo "Invalid quantity: [quantity]". Thêm phương thức getQuantity(): int để trả về giá trị số lượng.
  • main.php: Thêm cả ba tệp ngoại lệ. Bạn sẽ nhận hai đầu vào: tên sản phẩm và số lượng, dưới dạng chuỗi cần chuyển thành số nguyên.

    Dựa trên giá trị số lượng, hãy ném ngoại lệ phù hợp:

    • Nếu số lượng nhỏ hơn 1, hãy ném ngoại lệ InvalidQuantityException
    • Nếu số lượng lớn hơn 100, hãy ném ngoại lệ OutOfStockException để mô phỏng tình trạng không đủ hàng
    • Nếu không, hãy in ra "Order placed: [quantity]x [productName]"

    Bắt ngoại lệ bằng hệ thống phân cấp. Trước tiên, hãy bắt InvalidQuantityException và in ra "Quantity error: [message] (value: [quantity])" bằng thông báo của ngoại lệ và phương thức getQuantity(). Sau đó, hãy bắt OutOfStockException và in ra "Stock error: [message] (product: [productName])" bằng thông báo của ngoại lệ và phương thức getProductName().

Hệ thống phân cấp này cho phép bạn xử lý riêng từng ngoại lệ cụ thể, đồng thời vẫn có thể bắt mọi vấn đề liên quan đến đơn hàng thông qua lớp cơ sở OrderException. Các phương thức tùy chỉnh trong mỗi ngoại lệ cung cấp thông tin mà ngoại lệ chung không thể cung cấp.

Tự làm thử

<?php
// Nạp tất cả các tệp ngoại lệ
require_once 'OrderException.php';
require_once 'OutOfStockException.php';
require_once 'InvalidQuantityException.php';

// Đọc đầu vào
$productName = trim(fgets(STDIN));
$quantity = intval(trim(fgets(STDIN)));

// TODO: Dùng try-catch để xử lý đơn hàng
// Trong khối lệnh try:
//   - Nếu quantity < 1, ném InvalidQuantityException
//   - Nếu quantity > 100, ném OutOfStockException
//   - Nếu không, in ra "Order placed: [quantity]x [productName]"
//
// Bắt InvalidQuantityException trước:
//   - In ra "Quantity error: [message] (value: [quantity])" bằng getMessage() và getQuantity()
//
// Bắt OutOfStockException:
//   - In ra "Stock error: [message] (product: [productName])" bằng getMessage() và getProductName()

?>
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch PHP online