Bài này hướng dẫn bạn xử lý ngoại lệ trong PHP. Các ngoại lệ được sử dụng để thay đổi luồng thông thường của tập lệnh nếu xảy ra lỗi được chỉ định.
Nội dung chính
Ngoại lệ là gì?
Xử lý ngoại lệ được sử dụng để thay đổi luồng bình thường của chương trình nếu xảy ra một lỗi cụ thể (đặc biệt). Tình trạng này được gọi là ngoại lệ.
Đây là những gì thường xảy ra khi một ngoại lệ được kích hoạt:
- Trạng thái code hiện tại được lưu.
- Việc thực thi code sẽ chuyển sang một hàm xử lý ngoại lệ được xác định trước (tùy chỉnh).
- Tùy thuộc vào tình huống, trình xử lý có thể tiếp tục thực hiện từ trạng thái mã đã lưu, chấm dứt thực thi tập lệnh hoặc tiếp tục tập lệnh từ một vị trí khác trong tập lệnh.
Các phương thức xử lý ngoại lệ trong PHP:
- Sử dụng try, throw và catch.
- Tạo lớp ngoại lệ tùy chỉnh.
- Xử lý nhiều ngoại lệ.
- Ném lại một ngoại lệ.
- Thiết lập trình xử lý ngoại lệ cao cấp.
Lưu ý: Ngoại lệ chỉ nên được sử dụng với các điều kiện lỗi và không được sử dụng để nhảy đến một vị trí khác trong tập lệnh tại một điểm cụ thể.
Sử dụng try, throw và catch
- try - Một hàm sử dụng ngoại lệ phải ở trong khối "try". Nếu ngoại lệ không xảy ra, code sẽ tiếp tục như bình thường. Tuy nhiên, nếu ngoại lệ xảy ra, ngoại lệ bị "throw".
- throw - Đây là cách bạn kích hoạt ngoại lệ. Mỗi "throw" phải có ít nhất một "try".
- catch - Một khối "catch" bắt một ngoại lệ và tạo một đối tượng chứa thông tin ngoại lệ.
Ví dụ sử dụng khối try và throw nhưng không catch ngoại lệ
Khi một ngoại lệ được ném, khối lệnh sau nó sẽ không được thực thi, và PHP sẽ cố gắng tìm khối "catch" phù hợp.
Nếu một ngoại lệ không bị bắt, một lỗi nghiêm trọng sẽ được đưa ra với một thông báo "Uncaught Exception".
Hãy thử ném một ngoại lệ mà không bắt nó:
<?php //tạo hàm với một ngoại lệ function checkNum($number) { if($number>1) { throw new Exception("Giá trị phải nhỏ hơn hoặc bằng 1."); } return true; } //kích hoạt ngoại lệ checkNum(2); ?>
Kết quả:
Fatal error: Uncaught Exception: Giá trị phải nhỏ hơn hoặc bằng 1. in C:\xampp\htdocs\php\vi-du-ngoai-le-1.php:5 Stack trace: #0 C:\xampp\htdocs\php\vi-du-ngoai-le-1.php(11): checkNum(2) #1 {main} thrown in C:\xampp\htdocs\php\vi-du-ngoai-le-1.php on line 5
Ví dụ sử dụng try, throw và catch
Để tránh lỗi từ ví dụ trên, chúng ta cần phải sử dụng đối tượng Exception thích hợp với khối catch để xử lý một ngoại lệ.
<?php //tạo hàm và throw một ngoại lệ function checkNum($number) { if($number > 1) { throw new Exception("Giá trị phải nhỏ hơn hoặc bằng 1."); } return true; } //kích hoạt ngoại lệ trong khối "try" try { checkNum(2); // nếu ngoại lệ được ném ra thì lệnh sau không được thực thi echo 'Number nhỏ hơn hoặc bằng 1.'; } //catch exception catch(Exception $e) { echo 'Message: ' .$e->getMessage(); } ?>
Kết quả:
Message: Giá trị phải nhỏ hơn hoặc bằng 1.
Giải thích ví dụ:
Đoạn mã trên ném một ngoại lệ và bắt nó:
- Hàm checkNum() được tạo. Nó sẽ kiểm tra nếu một số lớn hơn 1. Nếu có, một ngoại lệ được ném.
- Hàm checkNum() được gọi trong khối "try".
- Ngoại lệ trong hàm checkNum() được ném.
- Khối "catch" lấy ra ngoại lệ và tạo một đối tượng ($e) chứa thông tin ngoại lệ.
- Thông báo lỗi từ ngoại lệ được lặp lại bằng cách gọi $e->getMessage() từ đối tượng ngoại lệ.
Tạo một lớp ngoại lệ tùy chỉnh
Để tạo một trình xử lý ngoại lệ tùy chỉnh, bạn phải tạo một lớp đặc biệt với các hàm có thể được gọi khi một ngoại lệ xảy ra trong PHP. Lớp này phải được kế thừa lớp Exception.
Lớp ngoại lệ tùy chỉnh kế thừa các thuộc tính từ lớp Exception của PHP và bạn có thể thêm các hàm tùy chỉnh vào nó.
Ví dụ tạo lớp ngoại lệ tùy chỉnh:
<?php class CustomException extends Exception { public function errorMessage() { //error message $errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile() .': <b>'.$this->getMessage().'</b> is not a valid E-Mail address'; return $errorMsg; } } $email = "someone@example...com"; try { //check email hợp lệ if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) { //throw exception nếu email không hợp lệ throw new customException($email); } } catch (customException $e) { //hiển thị message echo $e->errorMessage(); } ?>
Kết quả:
Error on line 17 in C:\xampp\htdocs\php\vi-du-ngoai-le-3.php: someone@example...com is not a valid E-Mail address
Lớp mới là một bản sao của lớp Exception cũ với việc bổ sung hàm errorMessage(). Vì nó là một bản sao của lớp cũ, và nó kế thừa các thuộc tính và phương thức từ lớp cũ, chúng ta có thể sử dụng các phương thức lớp Exception như getLine() và getFile() và getMessage().
Giải thích ví dụ
Đoạn code trên ném một ngoại lệ và bắt nó với một lớp ngoại lệ tùy chỉnh:
- Lớp CustomException() được tạo ra như là một phần mở rộng của lớp Exception. Bằng cách này, nó kế thừa tất cả các phương thức và thuộc tính từ lớp ngoại lệ cũ.
- Hàm errorMessage() được tạo. Hàm này trả về một thông báo lỗi nếu địa chỉ e-mail không hợp lệ.
- Biến $email được đặt thành một chuỗi không phải là địa chỉ e-mail hợp lệ.
- Khối "try" được thực hiện và một ngoại lệ được ném vì địa chỉ e-mail không hợp lệ.
- Khối "catch" bắt được ngoại lệ và hiển thị thông báo lỗi.
Xử lý nhiều ngoại lệ
Có thể cho một tập lệnh sử dụng nhiều ngoại lệ để kiểm tra nhiều điều kiện.
Có thể sử dụng một số mệnh đề if..else, switch hoặc tổ hợp nhiều ngoại lệ. Những ngoại lệ này có thể sử dụng các lớp ngoại lệ khác nhau và trả về các thông báo lỗi khác nhau:
<?php class CustomException2 extends Exception { public function errorMessage() { //error message $errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile() .': <b>'.$this->getMessage().'</b> is not a valid E-Mail address.'; return $errorMsg; } } $email = "someone@example.com"; try { //check if if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) { //throw exception nếu email không hợp lệ throw new CustomException2($email); } //kiểm tra tồn tại chuỗi "example" trong địa chỉ email if(strpos($email, "example") !== FALSE) { throw new Exception("$email is an example e-mail."); } } catch (CustomException2 $e) { echo $e->errorMessage(); } catch(Exception $e) { echo $e->getMessage(); } ?>
Kết quả:
someone@example.com is an example e-mail.
Giải thích ví dụ
Đoạn mã trên kiểm tra hai điều kiện và ném một ngoại lệ nếu bất kỳ điều kiện nào không được đáp ứng:
- Lớp CustomException2() được tạo ra như là một phần mở rộng của lớp Exception. Bằng cách này, nó kế thừa tất cả các phương thức và thuộc tính từ lớp ngoại lệ cũ.
- Hàm errorMessage() được tạo. Hàm này trả về một thông báo lỗi nếu địa chỉ e-mail không hợp lệ.
- Biến $email được đặt thành một chuỗi là địa chỉ e-mail hợp lệ, nhưng chứa chuỗi "example".
- Khối "try" được thực hiện và một ngoại lệ không được ném vào điều kiện đầu tiên.
- Điều kiện thứ hai gây ra một ngoại lệ vì e-mail chứa chuỗi "example".
- Khối "catch" bắt được ngoại lệ và hiển thị thông báo lỗi chính xác.
Note: Nếu trường hợp ngoại lệ được ném ra khỏi lớp CustomException2 và không có khối catch CustomException2, chỉ có khối catch Exception, ngoại lệ sẽ được xử lý ở đó.
Ném lại một ngoại lệ
Đôi khi, khi một ngoại lệ được ném, bạn có thể muốn xử lý nó khác với cách tiêu chuẩn. Có thể ném một ngoại lệ lần thứ hai trong một khối "catch".
Tập lệnh nên ẩn các lỗi hệ thống khỏi người dùng. Lỗi hệ thống có thể quan trọng đối với nhà lập trình nhưng không quan trọng với người dùng. Để giúp người dùng dễ dàng hơn, bạn có thể ném lại ngoại lệ bằng thông điệp thân thiện với người dùng:
<?php class CustomException3 extends Exception { public function errorMessage() { //error message $errorMsg = $this->getMessage().' is not a valid E-Mail address.'; return $errorMsg; } } $email = "someone@example.com"; try { try { //kiểm tra tồn tại chuỗi "example" trong địa chỉ email if(strpos($email, "example") !== FALSE) { //throw exception nếu email không hợp lệ throw new Exception($email); } } catch(Exception $e) { //ném lại một ngoại lệ throw new CustomException3($email); } } catch (CustomException3 $e) { //hiển thị message echo $e->errorMessage(); } ?>
Kết quả:
someone@example.com is not a valid E-Mail address.
Giải thích ví dụ
Đoạn mã trên kiểm tra xem địa chỉ email có chứa chuỗi "example" trong đó hay không, nếu có, ngoại lệ sẽ được ném lại:
- Lớp CustomException3() được tạo ra như là một phần mở rộng của lớp Exception. Bằng cách này, nó kế thừa tất cả các phương thức và thuộc tính từ lớp ngoại lệ cũ.
- Hàm errorMessage() được tạo. Hàm này trả về một thông báo lỗi nếu địa chỉ e-mail không hợp lệ.
- Biến $email được đặt thành một chuỗi là địa chỉ e-mail hợp lệ, nhưng chứa chuỗi "example".
- Khối "try" chứa một khối "thử" khác để làm cho nó có thể ném lại ngoại lệ.
- Ngoại lệ được kích hoạt vì e-mail chứa chuỗi "example".
- Khối "catch" bắt ngoại lệ và trả lại "CustomException3".
- "CustomException3" bị bắt và hiển thị thông báo lỗi.
Nếu ngoại lệ không bị bắt trong khối "try" hiện tại của nó, nó sẽ tìm kiếm một khối catch có "cấp độ cao hơn".
Thiết lập trình xử lý ngoại lệ cao cấp
Hàm set_exception_handler() thiết lập một chức năng người dùng định nghĩa để xử lý tất cả các trường hợp ngoại lệ còn tự do:
<?php function myException($exception) { echo "<b>Exception:</b> " . $exception->getMessage(); } set_exception_handler('myException'); throw new Exception('Uncaught Exception occurred'); ?>
Kết quả:
Exception: Uncaught Exception occurred
Trong đoạn mã trên không có khối "catch". Thay vào đó, trình xử lý ngoại lệ cấp cao nhất được kích hoạt. Hàm này nên được sử dụng để bắt các ngoại lệ chưa được catch.
Quy tắc cho trường hợp ngoại lệ
- Code nên được đặt trong khối try, để giúp bắt (catch) các ngoại lệ có thể xảy ra.
- Mỗi khối try hoặc "throw" phải có ít nhất một khối catch tương ứng.
- Nhiều khối catch có thể được sử dụng để bắt các lớp ngoại lệ khác nhau.
- Có thể ném các ngoại lệ (hoặc được ném lại) vào khối catch trong khối try.
Một quy tắc đơn giản: Nếu bạn ném một cái gì đó, bạn phải bắt nó.