Trong bài hướng dẫn tự học lập trình PHP này, bạn sẽ học xử lý ngoại lệ bằng cách ném (throw) và bắt (catch) trong PHP.
Ngoại lệ là gì?
Một Ngoại lệ (Exception) là một tín hiệu chỉ ra một số loại sự kiện hoặc lỗi đặc biệt đã xảy ra. Các ngoại lệ có thể được gây ra do nhiều lý do,.
Ví dụ: Kết nối cơ sở dữ liệu hoặc truy vấn không thành công, tệp mà bạn đang cố truy cập không tồn tại, v.v.
PHP cung cấp một cơ chế xử lý ngoại lệ mạnh mẽ cho phép bạn xử lý các ngoại lệ một cách đơn giản.
Trái ngược với hệ thống xử lý lỗi trong PHP, xử lý ngoại lệ là phương pháp hướng đối tượng để xử lý lỗi, cung cấp hình thức báo cáo lỗi linh hoạt và có kiểm soát hơn.
Mô hình ngoại lệ được giới thiệu lần đầu tiên trong PHP 5.
Sử dụng Throw và cấu trúc Try…Catch để xử lý ngoại lệ trong PHP

Theo cách tiếp cận này, code chương trình được viết trong một khối try, một ngoại lệ có thể được ném ra bằng cách sử dụng câu lệnh throw.
Khi một sự kiện đặc biệt xảy ra trong quá trình thực thi code trong khối try. Nó sẽ được bắt và giải quyết bằng một hoặc nhiều khối bắt.
Ví dụ sau đây cho thấy cách xử lý ngoại lệ hoạt động trong PHP:
<?php
function division($dividend, $divisor){
// Ném ra ngoại lệ chia cho số 0
if($divisor == 0){
throw new Exception('Chia cho số 0.');
} else{
$quotient = $dividend / $divisor;
echo "<p>$dividend / $divisor = $quotient</p>";
}
}
try{
division(10, 2);
division(30, -4);
division(15, 0);
// Nếu ngoại lệ được ném ra thì dòng sau không được thực thi
echo '<p>Tất cả các phép chia thực hiện thành công.</p>';
} catch(Exception $e){
// Xử lý ngoại lệ
echo "<p>Ngoại lệ: " . $e->getMessage() . "</p>";
}
// Tiếp tục thực thi
echo "<p>Hello World!</p>";
?>
Nếu bạn chưa hiểu đoạn code trên thực hiện như thế nào. Vậy thì, chúng ta hãy đi qua từng phần của đoạn code này để hiểu rõ hơn.
Giải thích về cách xử lý ngoại lệ trong ví dụ trên
Hệ thống xử lý ngoại lệ của PHP về cơ bản có bốn phần: try, throw, catcht và Exception class.
Danh sách sau đây sẽ mô tả chính xác cách mỗi phần hoạt động:
- Hàm division() trong ví dụ trên kiểm tra xem một ước số có bằng 0 hay không. Nếu đúng như vậy, một ngoại lệ được ném ra thông qua câu lệnh throw của PHP. Nếu không, hàm này thực hiện phép chia bằng các số đã cho và hiển thị kết quả.
- Sau đó, hàm division() được gọi trong một khối try với các đối số khác nhau. Nếu một ngoại lệ được tạo trong khi thực thi code trong khối try, PHP sẽ dừng thực thi tại điểm đó và cố gắng tìm khối catch tương ứng. Nếu nó được tìm thấy, code trong khối catch đó được thực thi, nếu không, một lỗi nghiêm trọng (fatal error) sẽ được tạo ra.
- Khối catch thường bắt ngoại lệ được ném trong khối try và tạo một object($e) có chứa thông tin ngoại lệ. Thông báo lỗi từ đối tượng này có thể được truy xuất bằng phương thức getMessage() của Exception class.
Exception class của PHP cũng cung cấp các phương thức khác như getCode(), getFile(), getLine() và getTraceAsString() có thể được sử dụng để truy xuất ra các thông tin cần thiết cho việc gỡ lỗi chi tiết.
<?php
// Tắt báo cáo lỗi mặc định
error_reporting(0);
try{
$file = "somefile.txt";
// Có gắng mở file
$handle = fopen($file, "r");
if(!$handle){
throw new Exception("Không thể mở file!", 5);
}
// Cố gắng đọc nội dung file
$content = fread($handle, filesize($file));
if(!$content){
throw new Exception("Không thể đọc file!", 10);
}
// Đóng file
fclose($handle);
// Hiển thị nội dung
echo $content;
} catch(Exception $e){
echo "<h3>Ngoại lệ xảy ra!</h3>";
echo "<p>Error message: " . $e->getMessage() . "</p>";
echo "<p>File: " . $e->getFile() . "</p>";
echo "<p>Line: " . $e->getLine() . "</p>";
echo "<p>Error code: " . $e->getCode() . "</p>";
echo "<p>Trace: " . $e->getTraceAsString() . "</p>";
}
?>
Hàm constructor của Exception nhận một thông báo ngoại lệ và code ngoại lệ. Mặc dù thông báo ngoại lệ thường được sử dụng để hiển thị thông tin chung về những gì đã sai, code ngoại lệ có thể được sử dụng để phân loại lỗi.
Code ngoại lệ được cung cấp có thể được truy xuất sau thông qua phương thức getCode() của Exception class.
Lưu ý: Ngoại lệ chỉ nên được sử dụng để biểu thị các điều kiện đặc biệt. Chúng không nên được sử dụng để kiểm soát luồng ứng dụng thông thường, ví dụ: Nhảy đến một vị trí khác trong tập lệnh tại một điểm cụ thể. Làm như vậy sẽ ảnh hưởng không tốt đến hiệu suất của ứng dụng.
Cách xác định ngoại lệ tùy chỉnh
Bạn thậm chí có thể định nghĩa các trình xử lý ngoại lệ tùy chỉnh của riêng bạn để xử lý các loại ngoại lệ khác nhau theo một cách khác. Nó cho phép bạn sử dụng một khối catch riêng cho từng loại ngoại lệ.
Bạn có thể định nghĩa một ngoại lệ tùy chỉnh bằng cách mở rộng lớp Exception, vì Exception là lớp cơ sở cho tất cả các ngoại lệ.
Lớp ngoại lệ tùy chỉnh kế thừa tất cả các thuộc tính và phương thức từ lớp Exception của PHP.
Bạn cũng có thể thêm các phương thức tùy chỉnh của mình vào lớp ngoại lệ tùy chỉnh., hãy xem ví dụ sau:
<?php
// Mở rộng lớp Exception
class EmptyEmailException extends Exception {}
class InvalidEmailException extends Exception {}
$email = "hello@niithanoi.edu.vn";
try{
// Ném ra ngoại lệ nếu Email trống
if($email == ""){
throw new EmptyEmailException("<p>Bạn phải điền Email</p>");
}
// Ném ra ngoại lệ nếu Email không hợp lệ
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
throw new InvalidEmailException("<p><b>$email</b> không hợp lệ!</p>");
}
// Thông báo thành công nếu email hợp lệ
echo "<p>CHÚC MỪNG: Xác thực Email thành công.</p>";
} catch(EmptyEmailException $e){
echo $e->getMessage();
} catch(InvalidEmailException $e){
echo $e->getMessage();
}
?>
Trong ví dụ trên, chúng ta đã nhận được hai lớp ngoại lệ mới: EmptyEmailException và UnlimitedEmailException từ lớp cơ sở là Exception.
Nhiều khối catch được sử dụng để hiển thị các thông báo lỗi khác nhau, tùy thuộc vào loại ngoại lệ nào được ném ra.
Do các lớp ngoại lệ tùy chỉnh này kế thừa các thuộc tính và phương thức từ lớp Exception, nên chúng ta hoàn toàn có thể sử dụng các phương thức của lớp Exception như getMessage(), getLine(), getFile(), v.v. để lấy thông tin lỗi từ đối tượng ngoại lệ.
Thiết lập Xử lý ngoại lệ toàn cục trong PHP
Như chúng ta đã thảo luận trước đó trong chương này nếu một ngoại lệ không bị bắt, PHP tạo ra Lỗi nghiêm trọng với thông báo ‘Uncaught Exception …’.
Thông báo lỗi này có thể chứa thông tin nhạy cảm như tên file và số dòng nơi xảy ra sự cố. Nếu bạn không muốn để lộ thông tin đó cho người dùng, bạn có thể tạo một hàm tùy chỉnh và đăng ký nó với hàm set_exception_handler() để xử lý tất cả các ngoại lệ chưa được phát hiện.
<?php
function handleUncaughtException($e){
// Hiển thị thông báo lỗi chung cho người dùng
echo "Opps! Có lỗi xảy ra. Hãy thử lại hoặc liên hệ với chúng tôi nếu còn lỗi.";
// Lấy thông tin lỗi
$error = "Uncaught Exception: " . $message = date("Y-m-d H:i:s - ");
$error .= $e->getMessage() . " trong file " . $e->getFile() . " ở dòng " . $e->getLine() . "\n";
// Ghi nhật ký chi tiết lỗi
error_log($error, 3, "var/log/exceptionLog.log");
}
// Đăng ký xử lý ngoại lệ tùy chỉnh
set_exception_handler("handleUncaughtException");
// Ném ra một ngoại lệ
throw new Exception("Kiểm tra ngoại lệ!");
?>
Lưu ý: Một ngoại lệ chưa được lưu sẽ luôn dẫn đến việc chấm dứt tập lệnh. Vì thế, nếu bạn muốn tập lệnh tiếp tục thực thi ngoài điểm xảy ra ngoại lệ, bạn phải có ít nhất một khối catch tương ứng cho mỗi khối try.
Bạn đã hiểu về các xử lý ngoại lệ chưa?
Như vậy là trong bài này mình đã hướng dẫn bạn biết cách xử lý ngoại lệ trong PHP với việc sử dụng throw và try… catch.
- Tham khảo Khóa học PHP hoàn thiện từ Front end đến Back end nếu như bạn là người mới bắt đầu.
Nếu có bất cứ thắc mắc nào về vấn đề ngoại lệ trong PHP thì vui lòng để lại câu hỏi trong phần bình luận. Mình sẽ giải thích cho bạn.
Chúc bạn thành công!