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.
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ởOrderExceptionkế 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ớpOutOfStockExceptionkế 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ứcgetProductName(): stringđể trả về tên sản phẩm.InvalidQuantityException.php: Tạo lớpInvalidQuantityExceptionkế 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ứcgetQuantity(): 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
InvalidQuantityExceptionvà in ra"Quantity error: [message] (value: [quantity])"bằng thông báo của ngoại lệ và phương thứcgetQuantity(). Sau đó, hãy bắtOutOfStockExceptionvà in ra"Stock error: [message] (product: [productName])"bằng thông báo của ngoại lệ và phương thứcgetProductName().- Nếu số lượng nhỏ hơn 1, hãy ném ngoại lệ
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()
?>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
1Nền tảng về OOP
Tệp bên ngoàiGiới thiệu về OOPLớp và đối tượngTừ khóa $thisPhương thứcThuộc tínhHàm khởi tạo (__construct)Hàm hủy (__destruct)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnTừ khóa parent::Ghi đè phương thứcTừ khóa finalLớp trừu tượngÔn tập: hệ thống phân cấp nhân viên7Đóng gói
Công khai, được bảo vệ, riêng tưTìm hiểu sâu về bộ điều chỉnh quyền truy cậpGetter và setterẨn thông tinRút gọn hàm khởi tạo (8.0)Ôn tập: hệ thống hồ sơ học sinh2Không gian tên và tự động nạp
Giới thiệu về không gian tênTừ khóa useChuẩn tự động nạp PSR-4Trình tự động nạp của ComposerÔn tập: dự án có tổ chức5Giao diện và hợp đồng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnGiao diện và lớp trừu tượngGợi ý kiểu với giao diệnÔn tập: Máy tính hình học8Phương thức ma thuật
Giới thiệu về phương thức ma thuật__toString và __debugInfo__get, __set, __isset, __unset__call và __callStatic__clone và sao chép đối tượng__serialize và __unserializeÔn tập: Bộ sưu tập tùy chỉnh11Hệ thống kiểu dữ liệu và xử lý lỗi
Khai báo kiểu dữ liệuKiểu dữ liệu có thể nhận giá trị nullKiểu hợp và kiểu giaoCác lớp ngoại lệHệ thống phân cấp ngoại lệ tùy chỉnhTry, Catch, FinallyÔn tập: Trình xác thực biểu mẫu3Thuộc tính của lớp
Thuộc tính instance và staticHằng số trong lớpPhương thức và thuộc tính staticThuộc tính private và protectedThuộc tính chỉ đọc (PHP 8.1)Ôn tập: Trình quản lý tài khoản ngân hàng6Đa hình
Xem lại việc ghi đè phương thứcĐa hình qua giao diệnGợi ý kiểu và kiểu hợpLiên kết tĩnh muộnÔn tập: bộ xử lý thanh toánTự luyện tập: Trình biên dịch PHP online