Xử lý ngoại lệ trong PHP

Việc giải quyết tất cả lỗi và lỗi tiềm ẩn trong mã của bạn có vẻ như là một việc dễ dàng, nhưng trên thực tế không phải vậy. Thật khó để dự đoán mã của bạn sẽ hoạt động như thế nào, do đó bạn không thể viết mã để xử lý tất cả các lỗi tiềm ẩn xảy ra. Giải pháp đưa ra là viết trình xử lý ngoại lệ giúp chúng ta xác định rõ ràng những gì PHP nên làm nếu có vấn đề trong một khối mã. Mời bạn đọc cùng eLib tìm hiểu về cách xử lý ngoại lệ trong PHP qua bài viết dưới đây.

Xử lý ngoại lệ trong PHP

1. 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.

2. Các phương thức xử lý ngoại lệ trong PHP

Một số phương thức xử lý ngoại lệ

  • 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ể.

3. 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ệ.

4. 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.

5. 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.

6. 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".

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

8. 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ó.

Trên đây là bài viết của eLib.VN về xử lý ngoại lệ trong PHP. Trong quá trình lập trình, chúng ta thường sẽ gặp lỗi (ngoại lệ) hay còn gọi là Exception. Và khi nó xảy ra chúng ta cần phải giải quyết nó một cách đẹp đẽ để mang lại trải nghiệm tốt nhất cho người dùng. Hy vọng qua bài viết, bạn đọc sẽ biết cách xử lý ngoại lệ một cách thông minh nhất. Chúc các bạn thành công!

Ngày:10/10/2020 Chia sẻ bởi:

CÓ THỂ BẠN QUAN TÂM