Как поймать фатальную ошибку (`E_ERROR`) в PHP?
Я могу использовать set_error_handler()
для перехвата большинства ошибок PHP, но это не работает для фатальных ошибок (E_ERROR
), таких как вызов несуществующей функции. Существует ли другой способ перехвата этих ошибок?
Я пытаюсь отправить все ошибки с помощью mail()
и использую PHP версии 5.2.3.
5 ответ(ов)
В PHP 7 и выше фатальные ошибки или восстанавливаемые фатальные ошибки теперь выбрасывают экземпляры класса Error
. Как и любые другие исключения, объекты Error
можно перехватить с помощью блока try/catch
.
Пример:
<?php
$variable = 'not an object';
try {
$variable->method(); // Выбросит объект Error в PHP 7 и выше.
} catch (Error $e) {
// Обработка ошибки
echo $e->getMessage(); // Вызов метода method() на строке
}
Также можно использовать интерфейс Throwable
, чтобы перехватить все исключения.
Пример:
<?php
try {
undefinedFunctionCall();
} catch (Throwable $e) {
// Обработка ошибки
echo $e->getMessage(); // Вызов несуществующей функции undefinedFunctionCall()
}
Для получения дополнительной информации: PHP.net - ошибки в PHP 7
Вы не можете поймать или обработать фатальные ошибки, но вы можете их записать или сообщить об них. Для быстрого отладки я модифицировал один из ответов, добавив следующий простой код:
function __fatalHandler()
{
$error = error_get_last();
// Проверяем, является ли это фатальной ошибкой, иначе это нормальное завершение
if ($error !== NULL && in_array($error['type'],
array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING,
E_COMPILE_ERROR, E_COMPILE_WARNING, E_RECOVERABLE_ERROR))) {
echo "<pre>фатальная ошибка:\n";
print_r($error);
echo "</pre>";
die;
}
}
register_shutdown_function('__fatalHandler');
Этот код регистрирует функцию, которая будет вызвана при завершении скрипта. Внутри этой функции мы используем error_get_last()
, чтобы получить последнюю ошибку. Если это фатальная ошибка, мы выводим её на экран для отладки.
Вы разработали способ перехватывать все типы ошибок в PHP (почти все)! Я не уверен по поводу E_CORE_ERROR (думаю, что он не будет работать только для этой ошибки)! Но для других фатальных ошибок (E_ERROR, E_PARSE, E_COMPILE и т.д.) это работает отлично, используя всего одну функцию обработчика ошибок! Вот моё решение:
Добавьте следующий код в ваш главный файл (index.php):
<?php
define('E_FATAL', E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR |
E_COMPILE_ERROR | E_RECOVERABLE_ERROR);
define('ENV', 'dev');
// Переменные для пользовательской обработки ошибок
define('DISPLAY_ERRORS', TRUE);
define('ERROR_REPORTING', E_ALL | E_STRICT);
define('LOG_ERRORS', TRUE);
register_shutdown_function('shut');
set_error_handler('handler');
// Функция для перехвата ошибок, для которых нет пользовательской обработчика...
function shut(){
$error = error_get_last();
if($error && ($error['type'] & E_FATAL)){
handler($error['type'], $error['message'], $error['file'], $error['line']);
}
}
function handler($errno, $errstr, $errfile, $errline) {
switch ($errno){
case E_ERROR:
$typestr = 'E_ERROR'; break;
case E_WARNING:
$typestr = 'E_WARNING'; break;
case E_PARSE:
$typestr = 'E_PARSE'; break;
case E_NOTICE:
$typestr = 'E_NOTICE'; break;
case E_CORE_ERROR:
$typestr = 'E_CORE_ERROR'; break;
case E_CORE_WARNING:
$typestr = 'E_CORE_WARNING'; break;
case E_COMPILE_ERROR:
$typestr = 'E_COMPILE_ERROR'; break;
case E_COMPILE_WARNING:
$typestr = 'E_COMPILE_WARNING'; break;
case E_USER_ERROR:
$typestr = 'E_USER_ERROR'; break;
case E_USER_WARNING:
$typestr = 'E_USER_WARNING'; break;
case E_USER_NOTICE:
$typestr = 'E_USER_NOTICE'; break;
case E_STRICT:
$typestr = 'E_STRICT'; break;
case E_RECOVERABLE_ERROR:
$typestr = 'E_RECOVERABLE_ERROR'; break;
case E_DEPRECATED:
$typestr = 'E_DEPRECATED'; break;
case E_USER_DEPRECATED:
$typestr = 'E_USER_DEPRECATED'; break;
}
$message =
'<b>' . $typestr .
': </b>' . $errstr .
' в <b>' . $errfile .
'</b> на строке <b>' . $errline .
'</b><br/>';
if(($errno & E_FATAL) && ENV === 'production'){
header('Location: 500.html');
header('Status: 500 Internal Server Error');
}
if(!($errno & ERROR_REPORTING))
return;
if(DISPLAY_ERRORS)
printf('%s', $message);
// Логируем ошибку в файл журнала ошибок PHP...
if(LOG_ERRORS)
error_log(strip_tags($message), 0);
}
ob_start();
@include 'content.php';
ob_end_flush();
?>
Данный код позволяет вам перехватывать различные ошибки в PHP и обрабатывать их в одном месте. Если вы используете этот подход, он должен помочь вам избежать потери информации о фатальных ошибках и сделать ваш код более устойчивым. Не забудьте протестировать его в своем окружении разработки перед использованием на продакшн-сайте!
Вам не получится выбросить исключение в зарегистрированной функции завершения (shutdown function) таким образом:
<?php
function shutdown() {
if (($error = error_get_last())) {
ob_clean();
throw new Exception("фатальная ошибка");
}
}
try {
$x = null;
$x->method();
} catch(Exception $e) {
# Это не сработает
}
?>
Однако вы можете перехватить ошибку и перенаправить запрос на другую страницу.
<?php
function shutdown() {
if (($error = error_get_last())) {
ob_clean();
# Логируем событие, отправляем email и т.д.
header("Location: http://localhost/error-capture");
# С /error-capture. Вы также можете использовать другое
# перенаправление, например, на главную страницу
}
}
register_shutdown_function('shutdown');
$x = null;
$x->method();
?>
В этом примере, если в вашем коде произойдет ошибка, функция shutdown
выполнится в конце обработки скрипта и позволит вам обработать ошибку надлежащим образом, например, перенаправив пользователя на страницу с сообщением об ошибке.
Если вы используете PHP версии 5.1.0 или выше, вы можете реализовать обработку ошибок с помощью класса ErrorException
. Вот пример, как это сделать:
<?php
// Определяем обработчик ошибок
function exception_error_handler($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
// Устанавливаем наш обработчик ошибок
set_error_handler("exception_error_handler");
/* Генерируем исключение */
try
{
// Попробуйте сделать что-то, например, найти конец интернета
}
catch(ErrorException $e)
{
// Здесь можно обработать исключение $e любым удобным способом
}
?>
В этом коде сначала определяется функция-обработчик, которая преобразует стандартные ошибки в исключения. Затем используется set_error_handler
для установки этой функции как обработчика ошибок. В блоке try
можно выполнять код, который может вызвать ошибку, а в блоке catch
можно взять на себя обработку ошибки, обернутой в исключение.
UTF-8 на всех уровнях!
Сортировка двумерного массива по значению в столбце
Что такое потокобезопасность и непотокобезопасность в PHP?
Как передать переменные и данные из PHP в JavaScript?
Вставка нового элемента в массив в любом месте в PHP