所以,我一直在阅读PHP在线手册上的异常,并意识到我还没有理解final关键字的目的或真正必要性。我在这里读过一些帖子,所以我的问题略有不同。
我知道我们最终可以这样使用:
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 $e)
捕获LogicException
并且没有抛出异常,我们仍然会看到正在执行的函数,并且我们会看到"hi"消息。如本例所示
try {
throw new LogicException("Throw logic n");
} catch (LogicException $e) {
echo $e->getMessage();
}finally{
echo hi();
}
输出
// Throw logic
// Hi
因此,即使我们没有未捕获的异常,我们仍然看到该函数hi()
执行。为什么这样做,有什么用? 我认为最终块将用作最后的手段,以防万一没有捕获异常,即使不是这种情况,那么为什么要运行它呢?
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;
尝试尝试
在 最终返回 覆盖尝试中的返回:
function baz()
{
try {
return 'trying';
} finally {
return 'finally';
}
}
echo baz();
最后
注意此行为在 PHP 5 中是不同的:
最后最后
最后最后
最后
https://3v4l.org/biO4e
卓越回报
你可以让它看起来像抛出 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.
https://3v4l.org/2AYmF
但是你无法真正捕捉到我知道的"第一个"异常,以便在运行时做任何有趣的事情:
try {
try {
throw new Exception('try');
} finally {
throw new Exception('finally');
}
} catch (Exception $exception) {
echo 'caught ' . $exception->getMessage();
}
终于被抓住了
https://3v4l.org/Jknpm
*死
如果exit
或die
则finally
块将不会执行。
try {
echo "trying";
die;
} finally {
echo "finally";
}
echo "end";
尝试
https://3v4l.org/pc9oc
†硬件故障
最后,您应该了解,如果有人拔掉您服务器上的电源插头,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);