在 PHP 中如何使用关键字 'finally'?
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 解释器停止脚本。好的。从我读到的内容来看,finally 使我们能够执行函数 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 $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应该包含无论是否有异常都需要执行的所有代码。
最后没有:
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);
}
}
在函数 returned 后需要释放资源的情况下提供一些整理。
这在以下情况下变得更加有用:
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);
}
}
在这种情况下,您可以将每个 return 之前的所有必需 fclose
调用减少到将在方法 returns 之前执行的单个 fclose
调用但在任何其他代码之后。
finally
每执行一次*† 次
无论错误、异常,甚至 return
语句,finally
代码块都将 运行.
*如果 try
或 catch
块执行 die
/exit
.
,它将 而不是 运行
异常
我看到的一个常见用途是关闭长 运行ning worker 中的数据库连接 - 你希望每次都发生这种情况(有或没有例外)所以你不会以悬空结束阻止数据库服务器接受新连接的连接。
考虑这个 pseudo-code:
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
其中一个比较模糊的行为是它能够在 return 语句之后执行代码。
这里你可以在函数returned:
后设置一个变量
function foo(&$x)
{
try {
$x = 'trying';
return $x;
} finally {
$x = 'finally';
}
}
$bar = 'main';
echo foo($bar) . $bar;
tryingfinally
但作业将是 return在 try:
中编辑的内容
$bar = foo($bar);
echo $bar . $bar;
tryingtrying
和 returning 最终覆盖了 try:
中的 return
function baz()
{
try {
return 'trying';
} finally {
return 'finally';
}
}
echo baz();
finally
注意 此行为在 php 5:
中有所不同
finallyfinally
finallyfinally
finally
优秀Return
你可以让它看起来像同时抛出 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();
}
caught finally
* 死
如果你 exit
or die
那么 finally
块将不会执行。
try {
echo "trying";
die;
} finally {
echo "finally";
}
echo "end";
trying
† 硬件故障
最后,你应该明白,如果有人拔掉你服务器上的电源插头,finally
块将不会执行,虽然我没有测试过,但我希望内存耗尽也会跳过它。
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);
所以,我今天在 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 解释器停止脚本。好的。从我读到的内容来看,finally 使我们能够执行函数 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 $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应该包含无论是否有异常都需要执行的所有代码。
最后没有:
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);
}
}
在函数 returned 后需要释放资源的情况下提供一些整理。
这在以下情况下变得更加有用:
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);
}
}
在这种情况下,您可以将每个 return 之前的所有必需 fclose
调用减少到将在方法 returns 之前执行的单个 fclose
调用但在任何其他代码之后。
finally
每执行一次*† 次
无论错误、异常,甚至 return
语句,finally
代码块都将 运行.
*如果 try
或 catch
块执行 die
/exit
.
异常
我看到的一个常见用途是关闭长 运行ning worker 中的数据库连接 - 你希望每次都发生这种情况(有或没有例外)所以你不会以悬空结束阻止数据库服务器接受新连接的连接。
考虑这个 pseudo-code:
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
其中一个比较模糊的行为是它能够在 return 语句之后执行代码。
这里你可以在函数returned:
后设置一个变量function foo(&$x)
{
try {
$x = 'trying';
return $x;
} finally {
$x = 'finally';
}
}
$bar = 'main';
echo foo($bar) . $bar;
tryingfinally
但作业将是 return在 try:
中编辑的内容$bar = foo($bar);
echo $bar . $bar;
tryingtrying
和 returning 最终覆盖了 try:
中的 returnfunction baz()
{
try {
return 'trying';
} finally {
return 'finally';
}
}
echo baz();
finally
注意 此行为在 php 5:
中有所不同finallyfinally
finallyfinally
finally
优秀Return
你可以让它看起来像同时抛出 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();
}
caught finally
* 死
如果你 exit
or die
那么 finally
块将不会执行。
try {
echo "trying";
die;
} finally {
echo "finally";
}
echo "end";
trying
† 硬件故障
最后,你应该明白,如果有人拔掉你服务器上的电源插头,finally
块将不会执行,虽然我没有测试过,但我希望内存耗尽也会跳过它。
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);