Как поймать фатальную ошибку PHP (E_ERROR): ловушки и решения

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Как поймать фатальную ошибку PHP (E_ERROR) и не сойти с ума

Вы когда-нибудь видели это? Ваш сайт на PHP выдаёт пустую белую страницу без единой ошибки. Или, что ещё хуже, — страшное сообщение Fatal error: Uncaught Error.... Если вы разработчик, который работает с PHP, вы сталкивались с E_ERROR — самой неприятной разновидностью ошибок. В отличие от предупреждений (Warnings) или уведомлений (Notices), фатальная ошибка полностью останавливает выполнение скрипта. И самое обидное: стандартный блок try...catch её не ловит.

В этой статье мы разберём, как правильно перехватывать фатальные ошибки PHP, почему обычные методы не работают, и как сделать ваш код более устойчивым. Это не просто теория — мы напишем несколько реальных примеров, которые вы сможете сразу применить на своих проектах.

Почему try...catch не спасает от E_ERROR?

Давайте сразу развеем иллюзию: try...catch в PHP предназначен для обработки исключений (Exceptions). А E_ERROR — это ошибка (Error). Это разные сущности. PHP до версии 7.0 не позволял ловить фатальные ошибки вообще. Начиная с PHP 7, появился класс Error, который, как и Exception, реализует интерфейс Throwable. Но это не значит, что любой E_ERROR автоматически становится исключением. Например, ошибка нехватки памяти (Out of memory) или вызов несуществующего метода — это всё ещё фатальные ошибки, которые не всегда можно перехватить через try...catch.

Вот простой пример:

try {
    $obj = new NonExistentClass(); // Это вызовет E_ERROR
} catch (Throwable $e) {
    echo 'Поймали: ' . $e->getMessage();
}

В PHP 7+ этот код сработает, потому что Throwable включает и Error. Но если ошибка происходит на этапе компиляции (например, синтаксическая ошибка) или в shutdown-фазе — try...catch бесполезен.

Топ-3 фатальных ошибки PHP и как их избежать

1. Вызов несуществующего метода или класса

Самая частая фатальная ошибка — Call to undefined method или Class not found. Она возникает, когда вы пытаетесь вызвать метод, которого нет, или использовать класс, который не подключён.

Как избежать:

  • Всегда используйте автозагрузку классов (spl_autoload_register или Composer).
  • Проверяйте существование метода через method_exists().
if (method_exists($object, 'someMethod')) {
    $object->someMethod();
} else {
    // обработка
}

2. Переполнение памяти (Allowed memory size exhausted)

Ошибка Allowed memory size of X bytes exhausted — это фатальная ошибка, которая возникает, когда скрипт потребляет больше памяти, чем разрешено. Её нельзя перехватить обычным способом.

Как избежать:

  • Оптимизируйте запросы к базе данных.
  • Используйте генераторы (yield) для обработки больших массивов.
  • Увеличьте лимит памяти в php.ini или через ini_set('memory_limit', '256M').

3. Таймаут выполнения (Maximum execution time exceeded)

Хотя эта ошибка не всегда фатальная, в некоторых конфигурациях она останавливает выполнение скрипта полностью.

Как избежать:

  • Используйте set_time_limit(0) для длительных скриптов.
  • Разбивайте тяжёлые операции на части.

Как поймать фатальную ошибку PHP: 3 проверенных способа

Теперь перейдём к главному. Есть несколько техник, которые позволяют перехватить E_ERROR и выполнить код до того, как скрипт умрёт.

Способ 1. Использование register_shutdown_function()

Это самый надёжный метод. Функция register_shutdown_function() регистрирует callback, который будет выполнен после завершения скрипта — даже если произошла фатальная ошибка. Внутри неё можно проверить, была ли ошибка, с помощью error_get_last().

register_shutdown_function(function() {
    $error = error_get_last();
    if ($error !== null && $error['type'] === E_ERROR) {
        // Логируем ошибку
        error_log("Фатальная ошибка: " . $error['message']);
        // Показываем пользователю понятное сообщение
        echo "Что-то пошло не так. Мы уже работаем над этим.";
        // Можно отправить email администратору
        mail('admin@example.com', 'PHP Fatal Error', print_r($error, true));
    }
});

// Пример, который вызовет E_ERROR
$data = file_get_contents('http://несуществующий-сайт.xyz');

Важно: shutdown-функция не может предотвратить остановку скрипта, но она даёт вам шанс корректно завершить работу — записать лог, отправить уведомление, показать пользователю дружественную страницу.

Способ 2. Комбинация с set_error_handler()

Стандартный обработчик ошибок set_error_handler() не ловит E_ERROR. Но вы можете настроить его так, чтобы он преобразовывал некоторые ошибки в исключения. А E_ERROR обрабатывать через shutdown.

// Превращаем предупреждения в исключения
set_error_handler(function($severity, $message, $file, $line) {
    if (error_reporting() & $severity) {
        throw new ErrorException($message, 0, $severity, $file, $line);
    }
});

// Регистрируем shutdown для фатальных ошибок
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error !== null && $error['type'] === E_ERROR) {
        // Ваша логика
    }
});

Способ 3. Глобальный обработчик исключений set_exception_handler()

Этот метод работает для непойманных исключений (включая Error в PHP 7+). Если исключение не было перехвачено в try...catch, оно попадает в этот обработчик.

set_exception_handler(function(Throwable $e) {
    echo "Непойманное исключение: " . $e->getMessage();
    error_log("Exception: " . $e->getMessage());
});

Но помните: set_exception_handler не ловит E_ERROR, который не является исключением (например, ошибка памяти). Поэтому лучше комбинировать его с register_shutdown_function.

Реальный пример: как защитить сайт от фатальных ошибок

Давайте соберём всё вместе и напишем класс, который будет перех

Блоги

Рекомендаций по книгам