可以';t捕获符号致命错误异常


Can't catch symfony FatalErrorException

我有这样的代码:

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

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

因此,如果我的集合为空,那么collection::first()将返回false。然后getItem调用将抛出一个Symfony''Component''Debug''Exception''FatalErrorException,该异常不会被上面的代码捕获。

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

使用可抛出类而不是异常类:

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

由于致命错误和可恢复错误引发的PHP7.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

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

既然您已经拥有了所有这些元素,您就可以开始下一步了:正如异常的名称所说,这是一个FatalError(一个与PHP有关的概念,而不是与Symfony2有关;在这种情况下,他们为这个错误构建了一个包装类,可能是出于接口目的)。

PHP致命错误是不可捕捉的,因此将可能导致致命错误的代码保存在try ... catch块中是非常无用的

在尝试访问返回值之前,应尽可能检查返回值,这是一条常见且良好的规则。

更新

由于在PHP7发布后,我看到了对我的答案的赞成票,我想提醒一下,由于PHP7可能会捕获致命错误,所以这个答案仍然有效,但仅适用于PHP版本<7.

好的。我找到了一个变通办法。我使用属性访问器组件,它抛出简单的异常,而不是致命的错误。

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

适用于我(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