【问题标题】:Can't catch symfony FatalErrorException无法捕获 symfony FatalErrorException
【发布时间】:2015-04-09 00:04:54
【问题描述】:

我有这样的代码:

try {
    $var = $object->getCollection()->first()->getItem()->getName();
} catch(\Exception $e) {
    $var = null;
}

当然,我有交流变量和方法名称。这只是演示。

因此,如果我的集合为空,则 Collection::first() 将返回 false。然后 getItem 调用将抛出一个 Symfony\Component\Debug\Exception\FatalErrorException ,上面的代码不会捕获它。

我的问题是我怎样才能捕捉到这个异常?我有像这样的长链,其中有许多可以返回 null 的 getter。所以我更喜欢这种方式,而不是检查每个值是否为空。

【问题讨论】:

  • 你试过catch (\FatalErrorException)
  • 我试过 catch(Symfony\Component\Debug\Exception\FatalErrorException) 和 catch(\ErrorException)。

标签: php symfony exception-handling


【解决方案1】:

如您所见 here,FatalErrorException 扩展了 ErrorException (PHP),它扩展了自身 php Exception 类。

现在你已经拥有了所有这些元素,你已经准备好进行下一步了:正如异常的名称所说,这是一个 FatalError(一个与 PHP 相关的概念,与 Symfony2 无关;在这种情况下,他们为此错误,可能出于界面目的)。

PHP 致命错误不是可捕获的,因此将可能导致 FatalError 的代码保留在 try ... catch 块内是毫无用处的

作为一项通用且良好的规则,您应该在尝试访问返回值之前尽可能检查它们。

更新

因为我在 PHP7 发布之后看到有人对我的答案表示赞成,我想提醒一下 since PHP7 is possible to catch fatal errors,所以这个答案仍然有效,但仅适用于 PHP 版本

【讨论】:

  • 你知道与默认树枝过滤器具有相似功能的工具吗?
  • @Jumi:什么意思?
  • @Jumi:我知道“默认树枝过滤器”。我在这里无法理解的是“工具”是什么意思?什么工具?一个 PHP 的?
  • 是的。一个库,一个函数,让我远离为所有 getter 编写条件的东西。就像 symfony 属性访问器会返回一个对象,其中包含在链中失败的调用。
  • 我不知道你在做什么。顺便说一句,正如我告诉你的那样,跳过控件不是一个好习惯,因为最终可能会发现大问题并且你的代码很快就会变得不稳定
【解决方案2】:

好的。我找到了解决方法。我使用属性访问器组件,它会抛出简单的异常,而不是致命错误。

$pa = \Symfony\Component\PropertyAccess\PropertyAccess::createPropertyAccessor();
try {
    $var = $pa->getValue($object, 'collection[0].item.name');
} catch(\Exception $e) {
    $var = null;
}

【讨论】:

  • 对逻辑/控制流使用异常是个坏主意。我希望您不要将上述代码块发送到任何生产环境中。
  • @RaduMurzea 实际上,在 Python 等一些语言中,这是一种非常常见的模式,他们将其表示为“请求宽恕比请求许可更容易”。 (见en.wikipedia.org/wiki/Python_syntax_and_semantics#Exceptions
【解决方案3】:

为我工作(PHP 7.0,Symfony 3.0.9):

use Symfony\Component\Debug\Exception\FatalThrowableError;
...
try {
    throw new FatalErrorException("something happened!", 0, 1, __FILE__, __LINE__);
} catch (FatalErrorException $e) {
    echo "Caught exception of class: " . get_class($e) . PHP_EOL;
}

输出:

Caught exception of class: Symfony\Component\Debug\Exception\FatalErrorException

【讨论】:

    【解决方案4】:

    使用 Throwable 类代替 Exception 类:

    try {
        $var = $object->getCollection()->first()->getItem()->getName();
    } catch(\Throwable $e) {
        $var = null;
        $msg = $e->getMessage();
    }
    

    自 PHP 7.0 以来,致命错误和可恢复错误引发的异常是新的独立异常类的实例:Error。这个新的Error 类实现了Throwable 接口,它指定了与Exception 几乎相同的方法。因为Throwable 的层次结构更高,所以您可以同时捕获\Error 和\Exception。

    interface Throwable
    |- Exception implements Throwable
        |- ...
    |- Error implements Throwable
        |- TypeError extends Error
        |- ParseError extends Error
        |- ArithmeticError extends Error
            |- DivisionByZeroError extends ArithmeticError
        |- AssertionError extends Error
    

    【讨论】:

    • 我可以确认这解决了问题,但我不明白为什么。 Symfony 的 FatalErrorException 扩展了 \ErrorException,它扩展了 \Exception。 PHP 现在将Error 作为基类这一事实似乎无关紧要,因为它不在FatalErrorException 的继承层次结构中。谁能解释一下?
    • @ScottBuchanan 我今天发现了一些有趣的东西。我的问题是 Symfony 的 FatalThrowableError(它也扩展了 ErrorException)。我注意到,如果您在异常 try/catch 中手动抛出 FatalThrowableError,它就会被捕获。但是我在应用程序中看到了这种类型的未处理错误,这些错误源自异常尝试/捕获。我正在使用 Laravel 框架,我推断框架在我的处理程序没有捕获它并将其包装在 FatalThrowableError 之后,捕获了未处理的 TypeError(一个错误,而不是异常)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-24
    • 2016-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多