PHP – Exception Handling

Exceptions dùng để thay đổi luồng thông thường của script nếu phát hiện lỗi.

Exception là gì

Exception handling được dùng để thay đổi luồng thông thường của việc thực thi script nếu xảy ra một lỗi cụ thể

Dưới đây là những gì xảy ra khi exception được kích hoạt

  • Lưu trạng thái hiện tại
  • Việc thực thi script sẽ chuyển sang một hàm xử lý ngoại lệ được xác định trước.
  • 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 mã.

Chung ta tìm hiểu các phương thức xử lý error sau

  • Sử dụng Exceptions cơ bản
  • Tạo một custom exception handler
  • Multiple exceptions
  • Re-throwing một exception
  • Setting một top level exception handler

Sử dụng Exceptions cơ bản

Khi 1 exception được thrown (ném ra). Code bên dưới nó sẽ không thực thi, và PHP cố gắng tìm block “catch” phù hợp.

Nếu 1 lỗi không tìm được catch tương ứng, nó sẽ có lỗi “Uncaught Exception”

Ví dụ

<?php
//create function with an exception
function checkNum($number) {
  if($number>1) {
    throw new Exception("Value must be 1 or below");
  }
  return true;
}

//trigger exception
checkNum(2);
?>

Kết quả

Fatal error: Uncaught exception 'Exception'
with message 'Value must be 1 or below' in C:\webfolder\test.php:6
Stack trace: #0 C:\webfolder\test.php(12):
checkNum(28) #1 {main} thrown in C:\webfolder\test.php on line 6

Try, throw và catch

Để tránh lỗi như ví dụ trên. Chúng ta cần tạo code xử lý exception.

Một Code exception bao gồm:

  • try : Một function dùng exception phải ở trong block “try”. Nếu exception không được kích hoạt code sẽ tiếp tục như bình thường. Tuy nhiên, nếu ngoại lệ kích hoạt, thrown sẽ được kích hoạt.
  • throw : Thường được gọi là ném lỗi, khi throw được kích hoạt, nó sẽ tìm đến “catch”. Mỗi “throw” phải có ít nhất một “catch”
  • catch : Một block “catch” lấy ra ngoại lệ và tạo một đối tượng chứa ngoại lệ
<?php
//create function with an exception
function checkNum($number) {
  if($number>1) {
    throw new Exception("Value must be 1 or below");
  }
  return true;
}

//trigger exception in a "try" block
try {
  checkNum(2);
  //If the exception is thrown, this text will not be shown
  echo 'If you see this, the number is 1 or below';
}

//catch exception
catch(Exception $e) {
  echo 'Message: ' .$e->getMessage();
}
?>

Kết quả

Message: Value must be 1 or below
  • Hàm checkNum() 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 ra (thrown)
  • Hàm checkNum() được gọi trong block “try”.
  • Một exception trong checkNum() được thrown ra.
  • block “catch” sẽ bắt lấy exception và tạo object ($e) chứa exception
  • Thông báo lỗi được xuất ra bằng $e->getMessage() từ exception object.

Tạo Custom Exception Class

Để tạo custom exception handler bạn cần tạo 1 class với các function được gọi khi exception xuất hiện. Class này phải được extension từ exception class.

custom exception class kế thừa các thuộc tính từ exception class và bạn có thể thêm các function tùy chỉnh vào nó.

<?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 if
  if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
    //throw exception if email is not valid
    throw new customException($email);
  }
}

catch (customException $e) {
  //display custom message
  echo $e->errorMessage();
}
?>

Class được tạo kế thừa từ exception class và thêm function errorMessage(). Nó là bản sao và kế thừa các properties và methods từ exception class vì thế chúng ta có thể sử dụng các methods như getLine() and getFile() và getMessage().

Trong ví dụ trên

  • Class customException được tạo và kế thừa từ exception class
  • Function errorMessage() được thêm vào class customException. function 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 gán giá trị là string không phải là 1 email hợp lệ.
  • Code trong block “try” thực thi và exception được ném ra do email không hợp lệ.
  • Block “catch” sẽ bắt ngoại lệ và thông báo ra.

Multiple Exceptions

Trong script có thể sử dụng multiple exceptions, mỗi trường hợp sẽ có 1 exception.

Có thể sử dụng if..else, switch, hay kết hợp nhiều exceptions, các exceptions có thể sử dụng các class exception khác nhau và thông báo ra lỗi khác nhau.

<?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 if
  if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
    //throw exception if email is not valid
    throw new customException($email);
  }
  //check for "example" in mail address
  if(strpos($email, "example") !== FALSE) {
    throw new Exception("$email is an example e-mail");
  }
}

catch (customException $e) {
  echo $e->errorMessage();
}

catch(Exception $e) {
  echo $e->getMessage();
}
?>

Trong ví dụ trên:

Code sẽ kiểm tra 2 điều kiện, và ném ra lỗi nếu điều kiện không thỏa.

  • Class customException() được tạo và kế thừa từ exception class.
  • function errorMessage() được tạo và function 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 gán một chuỗi là địa chỉ e-mail hợp lệ, nhưng chứa chuỗi “example”
  • Khối “try” thực thi, exception đầu tiên không được ném ra vì email hợp lệ.
  • Exception thứ 2 được ném ra vì email chứa “example”.
  • Block “example” bắt các ngoại lệ và hiển thị thông báo.

Try…Catch lồng vào nhau

Trong một số trường hợp, bạn muốn ném ra lỗi từ trong block catch. Chúng ta có thể sử dụng Try…Catch lồng vào nhau.

<?php
class customException 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 {
    //check for "example" in mail address
    if(strpos($email, "example") !== FALSE) {
      //throw exception if email is not valid
      throw new Exception($email);
    }
  }
  catch(Exception $e) {
    //re-throw exception
    throw new customException($email);
  }
}

catch (customException $e) {
  //display custom message
  echo $e->errorMessage();
}
?>

Trong ví dụ sau:

  • Class customException được tạo và kế thừa từ exception class
  • Function errorMessage() được thêm vào class customException. function 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 gán một chuỗi là địa chỉ e-mail hợp lệ, nhưng chứa chuỗi “example”
  • Block “try” chứa 1 block “try” khác
  • Exception được kích hoạt vì e-mail chứa chuỗi “example”
  • Block “catch” sẽ bắt lỗi và ném lại qua “customException”.
  • “customException” sẽ bắt lỗi và hiển thị ra.

Đặt Trình xử lý ngoại lệ cấp cao nhất

function set_exception_handler() sẽ set 1 function do người dùng tạo làm trình xử lý cho tất cả exception không có “catch” tương ứng.

<?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 ví dụ trên, không có block “catch”, nhưng function myException được thiết lập thành trình xử lý ngoại lệ cấp cao nhất thông qua function set_exception_handler để bắt các exceptions không có block “catch”.

Chú ý 1 quy tắc cơ bản nhất của bài này là : Nếu bạn ném một cái gì đó, bạn phải bắt nó.