PHP中的異常處理機制

語言: CN / TW / HK

點選進入“PHP開源社群”    

免費獲取進階面試、文件、影片資源

1、異常概述

異常(Exception)是一種錯誤處理機制,用於在指定的錯誤發生時改變指令碼的正常流程。當異常被觸發時,當前程式碼狀態被儲存,程式碼執行被切換到預定義的異常處理器函式(如果有),根據情況,處理器也許會從儲存的程式碼狀態重新開始執行程式碼,終止指令碼執行,或從程式碼中另外的位置繼續執行指令碼.

2、異常的基本使用

當異常被丟擲時,其後的程式碼不會繼續執行,PHP 會嘗試查詢匹配的 “catch” 程式碼塊。如果異常沒有被捕獲,而且又沒使用 set_exception_handler() 作相應的處理的話,那麼將發生一個嚴重的錯誤(致命錯誤),並且輸出 “Uncaught Exception” (未捕獲異常)的錯誤訊息。

嘗試丟擲一個異常,同時不去捕獲它

//create function with an exception

function checkNum($number){

if($number>1){

throw new Exception("Value must be 1 or below");

}

}

//trigger exception

checkNum(2);

上面的程式碼會獲得類似這樣的一個錯誤:

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

注意:PHP預設是警告模式,如果需要對系統錯誤使用異常處理機制,則要在處理程式碼之前設定錯誤處理模式

set_error_handler(function(){

throw new Exception('錯誤!');

});

3、Try, throw 和 catch

正確的處理程式應當包括:

Try- 使用異常的函式應該位於 “try” 程式碼塊內。如果沒有觸發異常,則程式碼            將照常繼續執行。但是如果異常被觸發,會丟擲一個異常。

Throw- 這裡規定如何觸發異常。每一個 “throw” 必須對應至少一個 “catch”

Catch- “catch” 程式碼塊會捕獲異常,並建立一個包含異常資訊的物件.

//建立可丟擲一個異常的函式

function checkNum($number){

if($number>1){

throw new Exception("Value must be 1 or below");

}

}

//在 "try" 程式碼塊中觸發異常

try{

checkNum(2);

}catch(Exception $e) { //捕獲異常

echo 'File: '.$e->getFile().' line: '.$e->getLine().'<br>';

die('Message: '.$e->getMessage());

}

上面程式碼將獲得類似這樣一個錯誤:

File: E:\webdev\www\pdo\3.php line: 7

Message: Value must be 1 or below

程式碼解析:建立 checkNum() 函式。它檢測數字是否大於 1。如果是,則丟擲一個異常。在 “try” 程式碼塊中呼叫 checkNum(),函式checkNum() 函式中的異常被丟擲,“catch” 程式碼塊接收到該異常,並建立一個包含異常資訊的物件 ($e)。通過從這個 exception 物件輸出來自該異常的錯誤訊息

不過,為了遵循“每個 throw 必須對應一個 catch”的原則,可以設定一個頂層的異常處理器來處理漏掉的錯誤, 見第7點.

4、建立自定義的異常處理器

建立一個專門的類,當 PHP 中發生異常時,可呼叫其函式。該類必須是 exception 類的一個擴充套件。這個自定義的exception 類繼承了 PHP 的 exception 類的所有屬性,可向其新增自定義的函式。

class customException extends Exception{

public function errorMessage(){

return 'Error on line '.$this->getLine().' in '.$this->getFile().': <b>'.$this->getMessage().'</b> is not a valid E-Mail address';

}

}

$email = "[email protected]";

try{

//使用PHP過濾器驗證郵箱有效性

if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE){

throw new customException($email);

}

}catch (customException $e){

echo $e->errorMessage();

}

這個新的類是舊的 exception 類的副本,外加 errorMessage() 函式。正因為它是舊類的副本,因此它從舊類繼承了屬性和方法,我們可以使用 exception 類的方法,比如 getLine() 、 getFile() 以及 getMessage()。

上面的程式碼丟擲了一個異常,並通過一個自定義的 exception 類來捕獲它:建立 errorMessage() 函式。如果 e-mail 地址不合法,則該函式返回一條錯誤訊息

5、多個異常的捕獲

可以為一段指令碼使用多個異常,來檢測多種情況。可以使用多個 if…else 程式碼塊,或一個switch 程式碼塊,或者巢狀多個異常。這些異常能夠使用不同的 exception 類,並返回不同的錯誤訊息:

class customException extends Exception{

public function errorMessage(){

return = 'Error on line '.$this->getLine().' in '.$this->getFile().': <b>'.$this->getMessage().'</b> is not a valid E-Mail address';

}

}

$email = "[email protected]";

try{

if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE){

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

}

上面的程式碼測試了兩種條件,如何任何條件不成立,則丟擲一個異常:

執行 “try” 程式碼塊,在第一個條件下,不會丟擲異常。由於 e-mail 含有字串 “example”,第二個條件會觸發異常。“catch” 程式碼塊會捕獲異常,並顯示恰當的錯誤訊息,如果沒有捕獲 customException,只捕獲了 base exception,則在那裡處理異常。

6、重新丟擲異常

有時,當異常被丟擲時,也許希望以不同於標準的方式對它進行處理。可以在一個 “catch” 程式碼塊中再次丟擲異常。指令碼應該對使用者隱藏系統錯誤。對程式設計師來說,系統錯誤也許很重要,但是使用者對它們並不感興趣。為了讓使用者更容易使用,可以再次丟擲帶有對使用者比較友好的訊息的異常:

class customException extends Exception{

public function errorMessage(){

return $this->getMessage().' is not a valid E-Mail address.';

}

}

$email = "[email protected]";

try{

try{

if(strpos($email, "example") !== FALSE){

throw new Exception($email);

}

}catch(Exception $e){

//re-throw exception

throw new customException($email);

}

}catch (customException $e){

//display custom message

echo $e->errorMessage();

}

上面的程式碼檢測在郵件地址中是否含有字串 “example”。如果有,則再次丟擲異常:

把 $email 變數設定為一個有效的郵件地址,但含有字串 “example”。“try” 程式碼塊包含另一個 “try” 程式碼塊,這樣就可以再次丟擲異常。由於 e-mail 包含字串 “example”,因此觸發異常。“catch” 捕獲到該異常,並重新丟擲 “customException”。捕獲到 “customException”,並顯示一條錯誤訊息。

如果在其目前的 “try” 程式碼塊中異常沒有被捕獲,則它將在更高層級上查詢 catch 程式碼塊。

7、設定頂層異常處理器

set_exception_handler() 函式可設定處理所有未捕獲異常的使用者定義函式

function myException($exception){

echo "<b>Exception:</b> " , $exception->getMessage();

}

set_exception_handler('myException');

throw new Exception('Uncaught Exception occurred');

以上程式碼的輸出應該類似這樣:

Exception: Uncaught Exception occurred

在上面的程式碼中,不存在 “catch” 程式碼塊,而是觸發頂層的異常處理程式。應該使用此函式來捕獲所有未被捕獲的異常。

但是對於系統自動丟擲的錯誤,會先經過set_error_handler處理並丟擲異常才能被set_exception_handler處理

function myException($exception){

echo "<b>Exception:</b> " , $exception->getMessage();

}

set_exception_handler('myException');

set_error_handler(function(){

throw new Exception('錯誤!');

});

echo 10/0; //觸發被除數不能為0的警告

程式碼執行結果:Exception: 錯誤!

*宣告:本文於網路整理,版權歸原作者所有,如來源資訊有誤或侵犯權益,請聯絡我們刪除或授權事宜

END

PHP開源社群

掃描關注  進入”PHP資料“

免費獲取進階

面試、文件、影片資源

點選“檢視原文”獲取更多