Не удается поймать symfony FatalErrorException

У меня такой код:

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

Конечно, у меня есть коммуникативные имена переменных и методов. Это просто демонстрация.

Итак, если моя коллекция пуста, Collection:: first() вернет false. Затем вызов getItem выведет Symfony\Component\Debug\Exception\FatalErrorException, которое не будет уловлено кодом выше.

Мой вопрос в том, как я могу поймать это исключение? У меня длинная цепочка, подобная этой, с множеством геттеров, которые могут возвращать нуль. Поэтому я предпочитаю этот способ, а не проверку каждого значения для null.

Ответ 1

Ok. Я нашел обходное решение. Я использую компонент accessor, который генерирует простые исключения, а не фатальные ошибки.

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

Ответ 2

Используйте класс 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

Ответ 3

Как вы можете видеть здесь, FatalErrorException расширяет ErrorException (PHP), который расширяет сам класс php Exception.

Теперь, когда у вас есть все эти элементы, вы готовы к следующему шагу: как следует из названия исключения, это FatalError (концепция, связанная с PHP, а не с Symfony2; в этом случае они создали класс-оболочку для этой ошибки, может быть, для целей интерфейса).

Неустранимая ошибка PHP не поддается отлову, поэтому довольно бесполезно хранить код, который может вызвать FatalError, внутри блока try... catch

Как правило, вы должны проверять, когда возможно, возвращаемые значения, прежде чем пытаться получить к ним доступ.

Обновить

Так как после выхода PHP7 я увидел положительный ответ на свой ответ, я хотел бы предупредить, что поскольку PHP7 позволяет перехватывать фатальные ошибки, этот ответ по-прежнему действителен, но только для версий PHP <7.

Ответ 4

Работает для меня (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

Ответ 5

Можете ли вы попробовать это:

$foo = $object->getCollection()->first();
if($foo){
  $var = $foo->getItem()->getName();
} else {
    // fallback
}