Menu
CoddyTech

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 zero

Bạ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 complete

Khố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.

challenge icon

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ớp FileException tùy chỉnh kế thừa Exception. 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ớp FileProcessor mô 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 $isOpen thành true và in ra "Opening: [filename]". Nếu tên tệp là "invalid.txt", hãy ném một ngoại lệ FileException với thông báo "Cannot open file"
    • Một phương thức process(): void in ra "Processing file...". Nếu $isOpen là false, hãy ném một ngoại lệ RuntimeException với thông báo "File not open"
    • Một phương thức close(): void đặt $isOpen thành false và in ra "File closed"
    • Một phương thức isOpen(): bool trả về trạng thái hiện tại
  • 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 FileProcessor và dùng cấu trúc try-catch-finally để:

    • Trong khối try: gọi open() với tên tệp, sau đó 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 finally: kiểm tra xem tệp có đang mở hay không bằng isOpen(), nếu có thì gọi close(). Sau đó in ra "Cleanup complete"

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"

?>
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