PHP Try…Catch



在 PHP 中,try、catch、throwfinally 關鍵字用於處理異常。而錯誤是意外的程式結果,程式本身無法處理,程式必須使用 die() 或設定自定義錯誤處理程式來終止。

另一方面,異常是指意外情況,可以對其進行處理,以便程式在將其丟擲其正常流程後繼續執行。

異常可以被丟擲,並使用 PHP 程式碼中的 catch 關鍵字捕獲。可能發生異常的程式碼塊用 try 塊包圍。每個 try 必須至少有一個對應的 catch 或 finally 塊。

Try、Throw、Catch 和 Finally

這四個與異常相關的關鍵字具有以下作用:

  • Try - 將可能發生某些異常的程式碼塊放在“try”塊中。如果未觸發異常,則程式碼繼續執行。但是,如果確實發生了異常,則會“丟擲”。執行將停止,PHP 將尋找匹配的“catch”塊。如果未捕獲異常,則 PHP 會發出致命錯誤。

  • Throw - 這是觸發異常的方法。每個“throw”必須至少有一個“catch”或“finally”塊。

  • Catch - 一個塊,它檢索異常並建立一個包含異常資訊的物件。可以使用多個 catch 塊來捕獲不同的異常。

  • Finally - finally 塊中的程式碼始終在 throw 或 catch 塊之後執行。

示例

這是一個異常處理技術的示例。程式碼在瀏覽器上呈現兩個文字欄位,並要求使用者輸入兩個數字進行除法運算。如果第二個數字(分母)為 0,則會丟擲異常,程式進入 catch 塊並列印異常訊息。否則,將顯示除法的結果。

<html>
<body>
   <form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post">
      <h3>First No: <input type="text" name="first"/></h3>
      <h3>Second No: <input type="text" name="second"/></h3>
      <input type="submit" value="Submit" />
   </form>

   <?php
      if ($_SERVER["REQUEST_METHOD"] == "POST") {
         $x = $_POST['first'];
         $y = $_POST['second'];
         echo "$x $y";
         try {
            if ($y == 0) {
               throw new Exception("Division by Zero");
            }
            $z = $x/$y;
            echo "<h3>x = $x y = $y Division = $z<br>";
         }
         catch (Exception $e) {
            echo "<h3> Exception: " . $e->getMessage();
         }
      }
   ?>
</body>
</html>

它將產生以下輸出

Case 1: x = 10 y = 5 Division = 2

Case 2: x = 10 y = 0
Exception: Division by Zero

異常類

PHP 丟擲一個Exception 類的物件。在 PHP 中,Exception 類是使用者異常的基礎。它實現了 throwable 介面。

此類定義了以下方法:

getMessage()

此函式將異常訊息作為字串返回:

final public Exception::getMessage(): string

getCode()

此函式在 Exception 中將異常程式碼作為int返回:

final public Exception::getCode(): int

請檢視以下示例

try {
   throw new Exception("Some error message", 30);
} 
catch(Exception $e) {
   echo "The exception code is: " . $e->getCode();
}

getFile()

此函式返回建立異常的檔名:

final public Exception::getFile(): string

請檢視以下示例

try {
   if ($y == 0) {
      throw new Exception("Division by Zero");
   }
   $z = $x/$y;
   echo "<h3>x = $x y = $y Division = $z<br>";
}
catch (Exception $e) {
   echo "<h3> Exception: " . $e->getMessage(). " in " . $e->getFile();
}

它將產生以下輸出

Exception: Division by Zero in C:\xampp\htdocs\hello.php

getLine()

此函式返回建立異常的行號:

final public Exception::getLine(): int

示例

請檢視以下示例:

<?php
   if ($_SERVER["REQUEST_METHOD"] == "POST") {
      $x = $_POST['first'];
      $y = $_POST['second'];
      echo "$x $y";
      try {
         if ($y == 0) {
            throw new Exception("Division by Zero");
         }
         $z = $x/$y;
         echo "<h3>x = $x y = $y Division = $z<br>";
      }
      catch (Exception $e) {
         echo "<h3> Exception: " . $e->getMessage(). " in " . $e->getLine() . " of " . $e->getFile();
      }
   }
?>

它將產生以下輸出

Exception: Division by Zero in 21 of C:\xampp\htdocs\hello.php

多個 Catch 塊

PHP 允許在 try 塊之後使用一系列 catch 塊來處理不同的異常情況。可以使用多個catch塊來處理預定義的異常和錯誤以及使用者定義的異常。

示例

以下示例使用catch塊來處理 DivisioByZeroError、TypeError、ArgumentCountError 和 InvalidArgumentException 條件。還有一個catch塊用於處理通用 Exception。

<?php
   declare(strict_types=1);
   function divide(int $a, int $b) : int {
      return $a / $b;
   }
   $a=10;
   $b=0;
   try {
   if (!$b) {
      throw new DivisionByZeroError('Division by zero.');
      if (is_int($a)==FALSE || is_int($b)==FALSE)
      throw new InvalidArgumentException("Invalid type of arguments");
      $result=divide($a, $b);
      echo $result;
   }
   
   // if argument types not matching
   catch (TypeError $x) {
      echo $x->getMessage();
   }

   // if denominator is 0
   catch (DivisionByZeroError $y) {
      echo $y->getMessage();
   }

   // if number of arguments not equal to 2
   catch (ArgumentCountError $z) {
      echo $z->getMessage();
   }

   // if argument types not matching
   catch (InvalidArgumentException $i) {
      echo $i->getMessage();
   }

   // any uncaught exception
   catch (Exception $ex) {
      echo $ex->getMessage();
   }	
?>

首先,由於分母為 0,因此將顯示“除以 0”錯誤:

Division by 0

設定$b=3,這將導致 TypeError,因為 divide 函式預期返回整數,但除法結果為float

divide(): Return value must be of type int, float returned

如果只將一個變數傳遞給 divide 函式,透過更改$res=divide($a); 這將導致ArgumentCountError

Too few arguments to function divide(), 1 passed in C:\xampp\htdocs\hello.php on line 16 and exactly 2 expected

如果其中一個引數不是整數,則為InvalidArgumentException的情況。將$b更改為字串:

Invalid type of arguments

Finally 塊

除了catch塊之外,還可以指定finally塊,或者用finally塊代替catch塊。無論是否丟擲異常,finally塊中的程式碼都將在trycatch塊之後執行,並在正常執行恢復之前執行。

try {
   if ($y == 0) {
      throw new Exception("Division by Zero");
   }
   $z = $x/$y;
   echo "<h3>x = $x y = $y Division = $z </h3><br>";
}
catch (Exception $e) {
   echo "<h3> Exception: " . $e->getMessage(). "</h3>";
}
finally {
   echo "<h3>End of try - catch - finally</h3>";
}

它將產生以下輸出:

情況1:

x = 10 y = 5 Division = 2
End of try - catch – finally

情況2:

X=10 y=0
Exception: Division by Zero
End of try - catch – finally

帶有返回語句的Finally

try塊或catch塊(或兩者)包含return語句時,finally塊的行為比較特殊。通常,return語句會導致程式控制權返回到呼叫位置。但是,在包含try/catch塊且帶有return語句的函式中,finally塊中的語句將在返回之前首先執行。

示例

在下面的示例中,div() 函式具有“try-catch-finally”結構。try塊在沒有異常的情況下返回除法的結果。如果發生異常,catch塊將返回錯誤訊息。但是,在這兩種情況下,finally塊中的語句都會首先執行。

<?php
   function div($x, $y) {
      try {
         if ($y==0)
         throw new Exception("Division by 0");
         else
         $res=$x/$y;;
         return $res;
      } 
      catch (Exception $e) {
         return $e->getMessage();
      }
      finally {
         echo "This block is always executed\n";
      }
   }
   $x=10;
   $y=0;
   echo div($x,$y);
?>

它將產生以下輸出

This block is always executed
Division by 0
廣告