在PHP中try-catch的性能

时间:2020-03-06 14:27:15  来源:igfitidea点击:

在PHP 5中使用try-catch语句时,要考虑什么样的性能影响?

以前,我已经在网上阅读了一些有关该主题的古老的,看似矛盾的信息。我目前必须使用的许多框架都是在php 4上创建的,并且缺少php 5的许多优点。因此,我在使用try-catchs与php方面没有太多经验。

解决方案

一般来说,它们很昂贵,而在PHP中并不值得。

由于它是一种检查表达式语言,因此我们必须捕获任何引发异常的内容。

当处理不会抛出的旧代码和会抛出的新代码时,只会导致混乱。

祝你好运!

我在Google上没有找到有关Try / Catch性能的任何信息,但是使用循环抛出错误而不是IF语句进行的简单测试在5,000个循环中产生了329ms和6ms。

通常,使用异常来防止意外失败,并在代码中使用错误检查来防止正常程序状态下的失败。为了显示:

  • 在数据库中找不到记录-有效状态,我们应该检查查询结果并适当地向用户发送消息。
  • 尝试获取记录时发生SQL错误-意外失败,该记录可能存在或者可能不存在,但是我们遇到了程序错误-这是发生异常的好地方-在错误日志中记录错误,向管理员发送电子邮件堆栈跟踪并显示一条礼貌的错误消息通知用户,提示他出了点问题,我们正在努力解决。

异常的代价很高,但是除非我们使用它们来处理整个程序流,否则任何性能上的差异都不应该引起人们的注意。

要考虑的一件事是,没有引发异常的try块的开销与实际引发和捕获异常的开销是一个不同的问题。

如果仅在失败情况下引发异常,那么我们几乎可以肯定不关心性能,因为在每次执行程序时都不会失败很多次。如果我们无法解决问题(也就是:将头撞在砖墙上),那么应用程序可能会遇到比慢的问题更严重的问题。因此,除非我们因某种原因被迫将其用于常规控制流,否则不必担心引发异常的代价。

有人发布了一个答案,谈论引发异常的性能分析代码。我从来没有亲自测试过它,但是我有信心地预测,这将比不插入任何尝试块进出try块表现出更大的性能损失。

要考虑的另一件事是,在嵌套调用的深度很深的地方,在顶部单独进行一次try ... catch甚至比检查返回值和传播每次调用的错误要快得多。

相反,在这种情况下,我们发现将每个调用都包装在其自己的try ... catch块中,代码将变慢。和丑陋的。

我很无聊,并分析了以下内容(我省略了时序代码):

function no_except($a, $b) { 
    $a += $b;
    return $a;
}
function except($a, $b) { 
    try {
        $a += $b;
    } catch (Exception $e) {}
    return $a;
}

使用两个不同的循环:

echo 'no except with no surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    no_except(5, 7);
}
echo 'no except with surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    try {
        no_except(5, 7);
    } catch (Exception $e) {}
}
echo 'except with no surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    except(5, 7);
}
echo 'except with surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    try {
        except(5, 7);
    } catch (Exception $e) {}
}

在WinXP机器上运行1000000并运行apache和PHP 5.2.6:

no except with no surrounding try = 3.3296
no except with surrounding try = 3.4246
except with no surrounding try = 3.2548
except with surrounding try = 3.2913

这些结果是一致的,并且无论测试按什么顺序进行,都保持相似的比例。

结论:添加代码来处理罕见的异常并不比编写忽略异常的代码慢。

多数民众赞成在一个很好的问题!

我已经对其进行了很多次测试,并且从未发现任何性能问题;-)十年前,在C ++中确实如此,但是我认为,自从它如此有用和更加清洁以来,他们已经对其进行了很多改进。

但是我仍然害怕用它包围我的第一个入口点:

try {Controller::run();}catch(...)

我没有测试大量的函数调用和大包含....是否有人已经对其进行了全面测试?