Zarządzanie wyjątkami w PHP

Wyjątek (Exception) służy do zmiany normalnego przepływu skryptu w określonych sytuacjach błędów.

Co to jest wyjątek?

PHP 5 oferuje nową metodę obiektowego przetwarzania błędów.

Przetwarzanie wyjątków służy do zmiany normalnego przepływu skryptu w określonych sytuacjach błędów (wyjątków). Ta sytuacja nazywa się wyjątkiem.

Kiedy wyjątek jest wywoływany, zazwyczaj dzieje się następujące:

  • Bieżący stan kodu zostanie zachowany
  • Wykonywanie kodu przełączy się na zdefiniowaną funkcję handlera wyjątków
  • W zależności od sytuacji, handler może zacząć wykonywać kod od zachowanego stanu kodu, zakończyć wykonywanie skryptu lub kontynuować wykonywanie skryptu z innej lokalizacji kodu

Pokażemy różne metody przetwarzania błędów:

  • Podstawowe użycie wyjątków
  • Tworzenie własnego handlera wyjątków
  • Wiele wyjątków
  • Ponowne rzuwanie wyjątku
  • Ustawienie górnego handlera wyjątków

Podstawowe użycie wyjątków

Kiedy wyjątek jest rzucony, kod po nim nie będzie kontynuował wykonywania się, PHP spróbuje znaleźć dopasowany blok kodu "catch".

Jeśli wyjątek nie zostanie złapany i nie zostanie użyty set_exception_handler() do odpowiedniego przetwarzania, dojdzie do poważnego błędu (krytycznego błędu), i zostanie wyświetlony komunikat błędu "Nie złapany wyjątek" (nie złapany wyjątek).

Spróbujmy rzucić wyjątek, nie łapiąc go:

<?php
//stwórz funkcję z wyjątkiem
function checkNum($number)
 {
 if($number>1)
  {
  throw new Exception("Value must be 1 or below");
  }
 return true;
 }
//wywołaj wyjątek
checkNum(2);
?>

Powyższy kod może wywołać błąd podobny do tego:

Błąd krytyczny: Niespodziewany wyjątek 'Exception' 
z komunikatem 'Wartość musi być 1 lub poniżej' w C:\webfolder\test.php:6 
Śledzenie stosu: #0 C:\webfolder\test.php(12): 
checkNum(28) #1 {main} rzucony w C:\webfolder\test.php w wierszu 6

Try, throw i catch

Aby uniknąć błędów z powyższego przykładu, musimy stworzyć odpowiedni kod do przetwarzania wyjątków.

Poprawne przetwarzanie powinno obejmować:

  1. Spróbuj - funkcje wyjątkowe powinny być umieszczone w bloku kodu "try". Jeśli wyjątek nie zostanie wywołany, kod będzie kontynuował normalne wykonywanie. Ale jeśli wyjątek zostanie wywołany, zostanie rzucony wyjątek.
  2. Throw - Tutaj określa się, jak wywołać wyjątek. Każdy "throw" musi mieć przynajmniej jeden "catch"
  3. Catch - Blok "catch" przechwytuje wyjątek i tworzy obiekt zawierający informacje o wyjątku

Pozwólmy wywołać wyjątek:

<?php
//Tworzenie funkcji, która może rzucać wyjątek
function checkNum($number)
 {
 if($number>1)
  {
  throw new Exception("Value must be 1 or below");
  }
 return true;
 }
//Wywołanie wyjątku w bloku kodu "try"
try
 {
 checkNum(2);
 //Jeśli wyjątek zostanie rzucony, ten tekst nie zostanie wyświetlony
 echo 'If you see this, the number is 1 or below';
 }
//Złapanie wyjątku
catch(Exception $e)
 {
 echo 'Message: ' .$e->getMessage();
 }
?>

Powyższy kod może wyświetlić podobny błąd:

Message: Value must be 1 or below

例子解释:

Powyższy kod rzuca wyjątek i go łapie:

  1. Tworzenie funkcji checkNum(). Sprawdza, czy liczba jest większa niż 1. Jeśli tak, rzuca wyjątek.
  2. Wywołanie funkcji checkNum() w bloku kodu "try".
  3. Wyjątek w funkcji checkNum() jest rzucony
  4. Bloki kodu "catch" odbierają ten wyjątek i tworzą obiekt zawierający informacje o wyjątku ($e).
  5. Przez wywołanie $e->getMessage() z tego obiektu exception, wyświetlana jest komunikat błędu z tego wyjątku

Aby przestrzegać zasady „każdy throw musi mieć odpowiedni catch”, można ustawić wierzchołkowy program obsługi wyjątków, aby obsługiwał pominięte błędy.

Tworzenie niestandardowej klasy Exception

Tworzenie niestandardowego programu obsługi wyjątków jest bardzo proste. Prosto tworzymy specjalną klasę, do której można wywołać funkcje, gdy w PHP wystąpi wyjątek. Klasa musi być rozszerzeniem klasy exception.

Ta niestandardowa klasa exception dziedziczy wszystkie atrybuty klasy exception PHP, możesz dodać do niej niestandardowe funkcje.

Zaczynamy tworzyć klasę exception:

<?php
class customException extends Exception
 {
 public function errorMessage()
  {
  //error message
  $errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
  : <b>'.$this->getMessage().'</b> nie jest poprawnym adresem e-mail
  return $errorMsg;
  }
 }
$email = "someone@example...com";
try
 {
 //Sprawdź, czy 
 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();
 }
?>

Nowa klasa jest kopią starej klasy wyjątków, dodając funkcję errorMessage(). Ponieważ jest kopią starej klasy, dziedziczy atrybuty i metody ze starej klasy, możemy używać metod klasy wyjątków, takich jak getLine(), getFile() oraz getMessage().

例子解释:

Powyższy kod rzuca wyjątek i uchwytuje go za pomocą własnej klasy wyjątków:

  1. customException() 类是作为旧的 exception 类的一个扩展来创建的。这样它就继承了旧类的所有属性和方法。
  2. Utwórz funkcję errorMessage(). Jeśli adres e-mail jest nielegalny, funkcja ta zwraca wiadomość o błędzie
  3. Ustaw zmienną $email na ciąg znaków adresu e-mail nielegalnego
  4. Wykonaj blok "try", ponieważ adres e-mail jest nielegalny, zostanie rzucony wyjątek
  5. Blok "catch" uchwytuje wyjątek i wyświetla wiadomość o błędzie

Wiele wyjątków

Możesz użyć wielu wyjątków dla jednego skryptu, aby wykryć różne sytuacje.

Możesz użyć wielu bloków if..else, lub jednego bloku switch, lub wielokrotnego wcięcia wyjątków. Te wyjątki mogą używać różnych klas wyjątków i zwracać różne wiadomości o błędach:

<?php
class customException extends Exception
{
public function errorMessage()
{
//error message
$errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
: <b>'.$this->getMessage().'</b> nie jest poprawnym adresem e-mail
return $errorMsg;
}
}
$email = "someone@example.com";
try
 {
 //Sprawdź, czy 
 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();
 }
?>

例子解释:

Powyższy kod testuje dwa warunki, jeśli żaden z nich nie jest spełniony, zostanie rzucony wyjątek:

  1. customException() 类是作为旧的 exception 类的一个扩展来创建的。这样它就继承了旧类的所有属性和方法。
  2. 创建 errorMessage() 函数。如果 e-mail 地址不合法,则该函数返回一个错误消息。
  3. Wykonaj blok "try", pod warunkiem pierwszym, wyjątek nie zostanie rzucony.
  4. Ponieważ e-mail zawiera ciąg "example", druga warunek wywoła wyjątek.
  5. Blok "catch" uchwytuje wyjątek i wyświetla odpowiednią wiadomość o błędzie

Jeśli nie uchwyciliśmy customException, ale tylko base exception, przetwarzaj wyjątek tam.

Ponowne rzuwanie wyjątku

Czasami, gdy wyjątek jest rzucony, możesz chcieć go przetworzyć w sposób inny niż standardowy. Możesz ponownie rzucać wyjątek w bloku "catch".

The script should hide system errors from the user. System errors may be important for programmers, but users are not interested in them. To make it easier for users, you can re-throw exceptions with user-friendly messages:

<?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();
 }
?>

例子解释:

上面的代码检测在邮件地址中是否含有字符串 "example"。如果有,则再次抛出异常:

  1. customException() 类是作为旧的 exception 类的一个扩展来创建的。这样它就继承了旧类的所有属性和方法。
  2. 创建 errorMessage() 函数。如果 e-mail 地址不合法,则该函数返回一个错误消息。
  3. 把 $email 变量设置为一个有效的邮件地址,但含有字符串 "example"。
  4. "try" 代码块包含另一个 "try" 代码块,这样就可以再次抛出异常。
  5. 由于 e-mail 包含字符串 "example",因此触发异常。
  6. "catch" 捕获到该异常,并重新抛出 "customException"。
  7. 捕获到 "customException",并显示一条错误消息。

Jeśli wyjątek nie został ujęty w bieżącym bloku try, zostanie poszukiwany w wyższym poziomie bloków catch.

Ustawienie najwyższego poziomu handlera wyjątków (Top Level Exception Handler)

Funkcja set_exception_handler() może ustawić użytkownika-defined funkcję do obsługi wszystkich nieuchwyconych wyjątków.

<?php
function myException($exception)
{
echo "<b>Exception:</b> " , $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('Uncaught Exception occurred');
?>

Wyjście powyższego kodu powinno wyglądać podobnie:

Exception: Uncaught Exception occurred

W powyższym kodzie nie istnieje blok catch, ale jest uruchamiany program异常处理程序。Należy użyć tej funkcji, aby ująć wszystkie nieuchwycone wyjątki.

Zasady wyjątków

  • Kod wymagający obsługi wyjątków powinien być umieszczony w bloku try, aby ująć potencjalne wyjątki.
  • Każdy blok try lub throw musi mieć przynajmniej jeden blok catch.
  • Użycie wielu bloków catch pozwala na ujęcie różnych rodzajów wyjątków.
  • Można ponownie rzucać (re-thrown) wyjątki w bloku catch kodu try.

Krótko mówiąc: jeśli wyjątek został rzucony, musi zostać ujęty.