Php 7 trace fatal error
Обработчик исключений, настроенный для SimpleSAMLphp, скрывает фактическое местоположение ошибки при обработке фатальных ошибок в PHP 7. Вместо этого мы получаем трассировку стека, указывающую на обработчик ошибок:
Исключение SimpleSAML_Error_Exception: Ошибка 1 – вызов неопределенной функции invalidfunction()
Обратная трассировка:
2 /www/simplesamlphp/www/_include.php:58 (SimpleSAML_error_handler)
1 /www/simplesamlphp/www/_include.php:26 ( SimpleSAML_exception_handler)
0 [встроенный] (N /A)
Это вызвано изменением способа обработки ошибок в PHP 7. До PHP 7 PHP напрямую вызывал наш обработчик ошибок из местоположения ошибки. Это позволило нам захватить трассировку стека, указывающую на местоположение, в котором произошла ошибка.
После PHP 7 ошибка обрабатывается как обычное исключение. Это означает, что PHP будет разматывать стек в поисках обработчика исключений, прежде чем окончательно передать его SimpleSAML_exception_handler()-функции.
К сожалению, при этом теряется информация о том, где произошла ошибка, поскольку она сохраняется только в исходном исключении.
Лучшим способом решить эту проблему было бы не вызывать исходный обработчик ошибок, а просто обернуть ошибку в обычное необработанное исключение:
if (class_exists(‘Error’) && $exception instanceof Error) {
$e = new \SimpleSAML\Error\Error(‘UNHANDLEDEXCEPTION’, $exception);
$e->show();
}
Проблема в том, что Error класс не наследуется от Exception класса. Таким образом, конструктор для SimpleSAML\Error\Exception не позволяет нам включать его в качестве $cause параметра.
Чтобы исправить это, потребуется изменить SimpleSAML\Error\Exception класс и другие связанные классы, чтобы принимать как Exception, так и Error объект в качестве $cause параметра.
ThrowableИнтерфейс является общим для Exception и Error, но он существует только в PHP 7, поэтому мы не можем использовать его при поддержке PHP 5.
Мы должны иметь возможность сами определять интерфейс, который можно использовать, если PHP-version <7, поэтому я не вижу в этом большой проблемы…
PHP7: обработка исключений и ошибок
В предыдущих версиях PHP не было способа обрабатывать неустранимые ошибки в вашем коде. Установка глобального обработчика ошибок с помощью set_error_handler() функции не помогает, выполнение скрипта будет остановлено. Это происходит из-за движка. Были подняты неустранимые ошибки, которые можно исправить (например, предупреждения или устаревания). Но исключения генерируются. Это основное отличие с точки зрения выполнения скрипта.
В PHP5 существует 16 различных типов ошибок:
// Fatal errors
E_ERROR
E_CORE_ERROR
E_COMPILE_ERROR
E_USER_ERROR
// Recoverable fatal errors
E_RECOVERABLE_ERROR
// Parse error
E_PARSE
// Warnings
E_WARNING
E_CORE_WARNING
E_COMPILE_WARNING
E_USER_WARNING
// Others
E_DEPRECATED
E_USER_DEPRECATED
E_NOTICE
E_USER_NOTICE
E_STRICT
Первые четыре ошибки являются фатальными, они останавливают выполнение скрипта и не вызывают обработчик ошибок. E_RECOVERABLE_ERROR ведет себя как неустранимая ошибка, но вызывает обработчик ошибок. Есть некоторые проблемы с этой моделью неустранимых ошибок:
они не могут быть обработаны обычным образом (обработчик ошибок не вызывается)
finally блок не будет вызван
деструкторы не вызываются
Решение этих проблем достигается с помощью исключений. Теперь в PHP7 при возникновении фатальной или восстанавливаемой фатальной ошибки (E_ERROR и E_RECOVERABLE_ERROR) будет выдаваться специальное исключение, а не остановка скрипта:
<?php
// PHP 5+
$obj = ‘foo’;
$obj->method();
// Fatal error: Call to a member function method() on a non-object
Существует пять предопределенных подклассов Error базового класса:
TypeError – аргумент не соответствует требуемому типу подсказки
ParseError – eval не удается проанализировать данный код
AssertionError – ошибка утверждения (assert(…))
ArithmeticError – ошибка во время математической операции
DivizionByZeroError – подкласс ArithmeticError при делении на 0
Вот полная иерархия исключений в PHP7:
interface Throwable
|- Exception implements Throwable
|- Other Exception classes
|- Error implements Throwable
|- TypeError extends Error
|- ParseError extends Error
|- AssertionError extends Error
|- ArithmeticError extends Error
|- DivizionByZeroError extends ArithmeticError