Try, Catch, Finally
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 68 trên 91.
Bây giờ bạn đã biết cách tạo và ném ngoại lệ, bạn cần học cách bắt chúng. Cấu trúc try-catch-finally giúp bạn xử lý ngoại lệ một cách nhẹ nhàng thay vì để chúng làm ứng dụng của bạn gặp sự cố.
Bọc code có thể gây ra ngoại lệ trong khối try, sau đó xử lý ngoại lệ trong khối catch:
<?php
class Calculator {
public function divide(int $a, int $b): float {
if ($b === 0) {
throw new InvalidArgumentException("Cannot divide by zero");
}
return $a / $b;
}
}
$calc = new Calculator();
try {
echo $calc->divide(10, 0);
} catch (InvalidArgumentException $e) {
echo "Error: " . $e->getMessage();
}
Đầu ra:
Error: Cannot divide by zeroBạn có thể bắt nhiều loại ngoại lệ bằng nhiều khối catch. PHP kiểm tra chúng theo thứ tự, vì vậy hãy đặt các ngoại lệ cụ thể hơn trước:
<?php
try {
// đoạn code có thể gây lỗi
} catch (InvalidArgumentException $e) {
echo "Bad input: " . $e->getMessage();
} catch (Exception $e) {
echo "Something went wrong: " . $e->getMessage();
}
Khối lệnh finally chạy bất kể ngoại lệ có được ném ra hay bắt lại hay không. Khối này rất phù hợp cho các tác vụ dọn dẹp như đóng kết nối:
<?php
try {
echo "Attempting operation\n";
throw new Exception("Failed");
} catch (Exception $e) {
echo "Caught: " . $e->getMessage() . "\n";
} finally {
echo "Cleanup complete";
}
Đầu ra:
Attempting operation
Caught: Failed
Cleanup completeKhối finally vẫn chạy ngay cả khi bạn trả về từ bên trong khối try hoặc catch, nên rất đáng tin cậy để thực hiện các thao tác dọn dẹp thiết yếu.
Thử thách
DễHãy xây dựng một hệ thống xử lý tệp để minh họa cách try-catch-finally phối hợp với nhau nhằm xử lý lỗi một cách phù hợp, đồng thời luôn đảm bảo việc dọn dẹp.
Bạn sẽ tổ chức code trong ba tệp:
FileException.php: Tạo một lớpFileExceptiontùy chỉnh kế thừaException. Lớp này đại diện cho các lỗi liên quan đến tệp trong hệ thống của bạn.FileProcessor.php: Tạo một lớpFileProcessormô phỏng các thao tác với tệp. Hãy đưa tệp FileException vào. Lớp của bạn cần có:- Một thuộc tính boolean riêng tư
$isOpenđược khởi tạo với giá trịfalse - Một phương thức
open(string $filename): voidđặt$isOpenthànhtruevà in ra"Opening: [filename]". Nếu tên tệp là"invalid.txt", hãy ném một ngoại lệFileExceptionvới thông báo"Cannot open file" - Một phương thức
process(): voidin ra"Processing file...". Nếu$isOpenlàfalse, hãy ném một ngoại lệRuntimeExceptionvới thông báo"File not open" - Một phương thức
close(): voidđặt$isOpenthànhfalsevà in ra"File closed" - Một phương thức
isOpen(): booltrả về trạng thái hiện tại
- Một thuộc tính boolean riêng tư
main.php: Đưa tệp FileProcessor vào. Bạn sẽ nhận một đầu vào: tên tệp.Tạo một
FileProcessorvà dùng cấu trúctry-catch-finallyđể:- Trong khối
try: gọiopen()với tên tệp, sau đó gọiprocess() - Bắt
FileExceptiontrước và in ra"File error: [message]" - Bắt
RuntimeExceptionvà in ra"Runtime error: [message]" - Trong khối
finally: kiểm tra xem tệp có đang mở hay không bằngisOpen(), nếu có thì gọiclose(). Sau đó in ra"Cleanup complete"
- Trong khối
Khối finally đảm bảo việc dọn dẹp diễn ra dù các thao tác thành công hay thất bại. Mẫu này rất cần thiết khi quản lý tài nguyên như tệp, kết nối cơ sở dữ liệu hoặc socket mạng, những tài nguyên cần được dọn dẹp bất kể điều gì xảy ra trong quá trình xử lý.
Tự làm thử
<?php
require_once 'FileProcessor.php';
// Đọc đầu vào
$filename = trim(fgets(STDIN));
// TODO: Tạo một instance của FileProcessor
// TODO: Dùng cấu trúc try-catch-finally:
// - Trong khối lệnh try: gọi open() với tên tệp, rồi gọi process()
// - Bắt FileException trước và in ra "File error: [message]"
// - Bắt RuntimeException và in ra "Runtime error: [message]"
// - Trong khối lệnh finally: dùng isOpen() để kiểm tra tệp có đang mở không, nếu có thì gọi close()
// Sau đó in ra "Cleanup complete"
?>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