[英]How is the keyword 'finally' meant to be used in PHP?
所以,我今天一直在閱讀 PHP 在線手冊上的異常,並意識到我還沒有理解 finally 關鍵字的目的或真正必要性。 我在這里閱讀了一些帖子,所以我的問題略有不同。
我知道我們可以這樣使用finally:
function hi(){
return 'Hi';
}
try {
throw new LogicException("Throw logic \n");
} catch (InvalidArgumentException $e) {
echo $e->getMessage();
}
echo hi();
輸出:
Fatal error: Uncaught LogicException: Throw Logic in C:\Users\...a.php:167
Stack trace:
#0 {main}
thrown in C:\Users\...a.php on line 167
因此,在這種情況下,函數 hi(); 沒有被執行並且有充分的理由。 我知道如果不處理異常,php 解釋器會停止腳本。 好的。 到目前為止,從我閱讀的內容來看,最終使我們能夠執行函數 hi(); 即使沒有處理異常(即使我不知道為什么)
所以,這個我明白了。
try {
throw new LogicException("Throw logic \n");
} catch (InvalidArgumentException $e) {
echo $e->getMessage();
}finally{
echo hi();
}
輸出:
Hi
Fatal error: Uncaught LogicException: Throw Logic in C:\Users\...a.php:167
Stack trace:
#0 {main}
thrown in C:\Users\...a.php on line 167
這應該是異常錯誤以及來自函數的“hi”消息,即使是那些我不知道有任何用法的消息。 但我不明白這一點,即使我們用 catch ( LogicException
(LogicException $e)
捕獲 LogicException 並且沒有拋出異常,我們仍然會看到正在執行的函數,並且會看到“hi”消息。 如本例所示
try {
throw new LogicException("Throw logic \n");
} catch (LogicException $e) {
echo $e->getMessage();
}finally{
echo hi();
}
輸出
// Throw logic
// Hi
因此,即使我們沒有未捕獲的異常,我們仍然可以看到函數hi()
被執行。 為什么以及這樣做有什么用? 我認為 finally 塊將被用作萬一沒有捕獲異常的最后手段,即使情況並非如此,那為什么還要使用它來運行它呢?
finally
每* †次執行一次不管錯誤、異常,甚至return
語句, finally
代碼塊都會運行。
*如果try
或catch
塊執行die
/ exit
,它將不會運行。
我看到的一個常見用途是在長時間運行的工作人員中關閉數據庫連接 - 你希望每次都發生這種情況(有或沒有例外),這樣你就不會最終得到一個懸掛連接,阻止數據庫服務器接受新連接.
考慮這個偽代碼:
try {
$database->execute($sql);
} finally {
$database->close();
}
在這里,我們將始終關閉數據庫連接。 如果是正常查詢,我們在成功后關閉連接,腳本會繼續執行。
如果是一個錯誤的查詢,那么我們仍然在拋出異常后關閉,未捕獲的異常將導致腳本停止。
這是一個使用catch
進行一些日志記錄的示例。
try {
$database->execute($sql);
} catch (Exception $exception) {
$logger->error($exception->getMessage(), ['sql' => $sql]);
throw $exception;
} finally {
$database->close();
}
這將使它關閉連接,無論是否有異常。
比較晦澀的行為之一是它能夠在 return 語句之后執行代碼。
函數返回后,您可以在此處設置變量:
function foo(&$x)
{
try {
$x = 'trying';
return $x;
} finally {
$x = 'finally';
}
}
$bar = 'main';
echo foo($bar) . $bar;
終於嘗試
但是分配將是嘗試返回的內容:
$bar = foo($bar);
echo $bar . $bar;
嘗試嘗試
並在 finally 中返回會覆蓋 try 中的返回:
function baz()
{
try {
return 'trying';
} finally {
return 'finally';
}
}
echo baz();
最后
請注意,這種行為在 php 5 中有所不同:
終於終於
終於終於
最后
你可以讓它看起來像拋出 2 個異常同時冒泡:
try {
throw new Exception('try');
} finally {
throw new Exception('finally');
}
Fatal error: Uncaught Exception: try in /in/2AYmF:4 Stack trace: #0 {main} Next Exception: finally in /in/2AYmF:6 Stack trace: #0 {main} thrown in /in/2AYmF on line 6 Process exited with code 255.
但是你不能真正捕捉到我知道在運行時做任何有趣的事情的“第一個”異常:
try {
try {
throw new Exception('try');
} finally {
throw new Exception('finally');
}
} catch (Exception $exception) {
echo 'caught ' . $exception->getMessage();
}
終於抓到了
如果你exit
或die
,那么finally
塊將不會執行。
try {
echo "trying";
die;
} finally {
echo "finally";
}
echo "end";
試
最后,你應該明白,如果有人拔掉你服務器上的電源插頭, finally
塊將不會執行😉,雖然我沒有測試過,但我希望內存耗盡也會跳過它。
finally 應該包含任何需要執行的代碼,無論是否有異常。
沒有最后:
try {
$handle = fopen("file.txt");
//Do stuff
fclose($handle);
return something;
} catch (Exception $e) {
// Log
if (isset($handle) && $handle !== false) {
fclose($handle);
}
}
最后:
try {
$handle = fopen("file.txt");
return something;
} catch (Exception $e) {
// Log
} finally {
if (isset($handle) && $handle !== false) {
fclose($handle);
}
}
在函數返回后需要釋放資源的情況下提供一些整理。
這在以下情況下變得更加有用:
try {
$handle = fopen("file.txt");
if (case1) { return result1; }
if (case2) { return result2; }
if (case3) { return result3; }
if (case4) { return result4; }
} finally {
if (isset($handle) && $handle !== false) {
fclose($handle);
}
}
在這種情況下,您可以在每次返回之前將所有必需的fclose
調用減少為單個fclose
調用,該調用將在方法返回之前但在任何其他代碼之后執行。
try {
throw new LogicException("Throw logic \n"); -> LogicException thrown
} catch (InvalidArgumentException $e) { -> LogicException not catched
echo $e->getMessage();
}finally{
echo hi(); -> code executed. "Hi" printed out
}
LogicException is here -> Fatal error
所以在這種情況下:
try {
throw new LogicException("Throw logic \n"); -> LogicException thrown
} catch (InvalidArgumentException $e) { -> LogicException not catched
echo $e->getMessage();
}finally{
echo hi(); -> code executed
die();
}
由於 die 語句和最后一個變體,不會引發致命錯誤:
try {
throw new LogicException("Throw logic \n"); -> LogicException thrown
} catch (InvalidArgumentException $e) { -> LogicException not catched
echo $e->getMessage();
} catch (LogicException $e) { -> LogicException catched
echo $e->getMessage();
}finally{
echo hi(); -> code executed
}
我做了一個小單元測試來展示它是如何工作的
$a = 'a';
try {
$a .= 'b';
} catch (Exception $ex) {
$a .= 'e';
} finally {
$a .= 'f';
}
$a .= 'x';
$this->assertSame('abfx', $a);
$a = 'a';
try {
$a .= 'b';
throw new Exception();
$a .= '1';
} catch (Exception $ex) {
$a .= 'e';
} finally {
$a .= 'f';
}
$a .= 'x';
$this->assertSame('abefx', $a);
$a = 'a';
try {
try {
$a .= 'b';
throw new Exception();
$a .= '1';
} catch (Exception $ex) {
$a .= 'e';
throw $ex;
$a .= '2';
} finally {
$a .= 'f';
}
$a .= 'x';
} catch (Exception $ex) {
$a .= 'z';
}
$this->assertSame('abefz', $a);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.