PHP8 異常

2023-08-17 17:44 更新

目錄

  • 擴展(extend)異常處理類

PHP 有一個和其他語言相似的異常模型。在 PHP 里可以 throw 并捕獲(catch)異常。為了捕獲潛在的異常,代碼會包含在 try 塊里。每個 try 都必須至少有一個相應(yīng)的 catch 或 finally 塊。

如果拋出異常的函數(shù)作用域內(nèi)沒有 catch 塊,異常會沿調(diào)用?!跋蛏厦芭荨保钡秸业狡ヅ涞?nbsp;catch 塊。沿途會執(zhí)行所有遇到的 finally 塊。在沒有設(shè)置全局異常處理程序時,如果調(diào)用棧向上都沒有遇到匹配的 catch,程序會拋出 fatal 錯誤并終止。

拋出的對象必須是 instanceof Throwable。嘗試拋出其他對象會導致 PHP Fatal 錯誤。

PHP 8.0.0 起,throw 關(guān)鍵詞現(xiàn)在開始是表達式,可用于任何表達式上下文。在此之前,它是語句,必須獨占一行。

catch

catch 定義了處理拋出異常的方式。 catch 塊定義了它能處理的異常/錯誤的類型,并可以選擇將異常賦值到變量中。 (在 PHP 8.0.0 之前的版本中必須要賦值到變量) 如果遇到拋出對象的類型匹配了首個 catch 塊的異?;蝈e誤,將會處理該對象。

可用多個 catch 捕獲不同的異常類。 正常情況下(try 代碼塊里沒有拋出異常)會在最后一個定義的 catch 后面繼續(xù)執(zhí)行。 catch 代碼塊里也可以 throw 或者重新拋出異常。 不拋出的話,會在觸發(fā)的 catch 后面繼續(xù)執(zhí)行。

當 PHP 拋出一個異常時,將不會執(zhí)行后續(xù)的代碼語句,并會嘗試查找首個匹配的 catch 代碼塊。 如果沒有用 set_exception_handler() 設(shè)置異常處理函數(shù), PHP 會在異常未被捕獲時產(chǎn)生 Fatal 級錯誤,提示 "Uncaught Exception ..." 消息。

從 PHP 7.1.0 起 catch 可以用豎線符(|) 指定多個異常。 如果在不同的類層次結(jié)構(gòu)中,不同異常的異常需要用同樣的方式處理,就特別適用這種方式。

從 PHP 8.0.0 起,捕獲的異常不再強制要求指定變量名。 catch 代碼塊會在未指定時繼續(xù)執(zhí)行,只是無法訪問到拋出的對象。

finally

finally 代碼塊可以放在 catch 之后,或者直接代替它。 無論是否拋出了異常,在 try 和 catch 之后、在執(zhí)行后續(xù)代碼之前, 放在 finally 里的代碼總是會執(zhí)行。

值得注意的是 finally 和 return 語句之間存在相互影響。 如果在 try 或 catch 里遇到 return,仍然會執(zhí)行 finally 里的代碼。 而且,遇到 return 語句時,會先執(zhí)行 finally 再返回結(jié)果。 此外,如果 finally 里也包含了 return 語句,將返回 finally 里的值。

全局異常處理程序

當允許異常冒泡到全局作用域時,它可以被全局異常處理器捕獲到。 set_exception_handler() 可以設(shè)置一個函數(shù),在沒有調(diào)用其他塊時代替 catch。 在本質(zhì)上,實現(xiàn)的效果等同于整個程序被 try-catch 包裹起來, 而該函數(shù)就是 catch。

注釋

注意:PHP 內(nèi)部函數(shù)主要使用 錯誤報告, 只有一些現(xiàn)代 面向?qū)ο?nbsp;的擴展使用異常。 不過,錯誤很容易用 ErrorException 轉(zhuǎn)化成異常。 然而,這個技術(shù)方案僅適用非 Fatal 級的錯誤。示例 #1 將錯誤報告轉(zhuǎn)成異常
小技巧
PHP 標準庫(SPL) 提供了大量的 標準內(nèi)置異常。

示例

示例 #2 拋出一個異常

<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}

try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}

// 繼續(xù)執(zhí)行
echo "Hello World\n";
?>

以上示例會輸出:

0.2
Caught exception: Division by zero.
Hello World

示例 #3 帶 finally 塊的異常處理

<?php
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1/$x;
}

try {
echo inverse(5) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "First finally.\n";
}

try {
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
} finally {
echo "Second finally.\n";
}

// 繼續(xù)執(zhí)行
echo "Hello World\n";
?>

以上示例會輸出:

0.2
First finally.
Caught exception: Division by zero.
Second finally.
Hello World

示例 #4 finally 和 return 相互之間的影響

<?php

function test() {
try {
throw new Exception('foo');
} catch (Exception $e) {
return 'catch';
} finally {
return 'finally';
}
}

echo test();
?>

以上示例會輸出:

finally

示例 #5 異常嵌套

<?php

class MyException extends Exception { }

class Test {
public function testing() {
try {
try {
throw new MyException('foo!');
} catch (MyException $e) {
// 重新 throw
throw $e;
}
} catch (Exception $e) {
var_dump($e->getMessage());
}
}
}

$foo = new Test;
$foo->testing();

?>

以上示例會輸出:

string(4) "foo!"

示例 #6 多個異常的捕獲處理

<?php

class MyException extends Exception { }

class MyOtherException extends Exception { }

class Test {
public function testing() {
try {
throw new MyException();
} catch (MyException | MyOtherException $e) {
var_dump(get_class($e));
}
}
}

$foo = new Test;
$foo->testing();

?>

以上示例會輸出:

string(11) "MyException"

示例 #7 忽略捕獲的變量

僅僅在 PHP 8.0.0 及以上版本有效

<?php

function test() {
throw new SpecificException('Oopsie');
}

try {
test();
} catch (SpecificException) {
print "A SpecificException was thrown, but we don't care about the details.";
}
?>

示例 #8 以表達式的形式拋出

僅僅在 PHP 8.0.0 及以上版本有效

<?php

class SpecificException extends Exception {}

function test() {
do_something_risky() or throw new Exception('It did not work');
}

try {
test();
} catch (Exception $e) {
print $e->getMessage();
}
?>


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號