register_shutdown_function(callable $callback, mixed ...$args): void
Расскажите об этой функции всё, что знаете.
register_shutdown_function()
регистрирует функцию, которая выполняется после завершения скрипта, даже при фатальных ошибках или exit(). Используется для обработки фатальных ошибок (через error_get_last()
), гарантированного освобождения ресурсов и финального логирования.
Полный ответ:
1. Основное назначение и синтаксис
register_shutdown_function()
регистрирует функцию, которая будет выполнена после завершения работы скрипта или при его аварийном завершении.
register_shutdown_function(callable $callback, mixed ...$args): void
- Можно зарегистрировать несколько функций — они выполнятся в порядке регистрации
- Функции выполняются даже при фатальных ошибках или
exit()/die()
2. Когда вызываются shutdown-функции?
Функции выполняются в следующих случаях:
- Нормальное завершение скрипта
- Вызов
exit()
илиdie()
- Фатальные ошибки (Fatal errors)
- Превышение лимита времени выполнения (max_execution_time)
- Превышение лимита памяти (memory_limit)
- Парсер обнаружил фатальную ошибку (только некоторые типы)
3. Практическое применение
Обработка фатальных ошибок:
register_shutdown_function(function() {
$error = error_get_last();
if ($error !== null && $error['type'] === E_ERROR) {
// Логируем фатальную ошибку
error_log("Fatal error: {$error['message']} in {$error['file']}:{$error['line']}");
// Показываем пользователю友好ское сообщение
if (headers_sent() === false) {
http_response_code(500);
echo "Извините, произошла внутренняя ошибка";
}
}
});
// Вызовет фатальную ошибку, но shutdown function выполнится
nonexistent_function();
Гарантированное освобождение ресурсов:
$dbConnection = null;
$fileHandle = null;
register_shutdown_function(function() use (&$dbConnection, &$fileHandle) {
if ($dbConnection !== null) {
$dbConnection->close();
}
if ($fileHandle !== null) {
fclose($fileHandle);
}
echo "Ресурсы освобождены";
});
// Даже если здесь произойдет ошибка, соединение закроется
$dbConnection = new DatabaseConnection();
some_risky_operation();
Логирование времени выполнения:
$startTime = microtime(true);
register_shutdown_function(function() use ($startTime) {
$executionTime = microtime(true) - $startTime;
file_put_contents('performance.log',
"Script executed in: " . round($executionTime, 4) . " seconds" . PHP_EOL,
FILE_APPEND
);
});
4. Работа с error_get_last()
error_get_last()
возвращает информацию о последней произошедшей ошибке — это ключевой инструмент в shutdown functions.
register_shutdown_function(function() {
$error = error_get_last();
if ($error !== null) {
switch ($error['type']) {
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
// Критическая ошибка - логируем и уведомляем
error_log("CRITICAL: {$error['message']}");
break;
case E_WARNING:
case E_NOTICE:
// Менее критичные ошибки
break;
}
}
});
5. Особенности и ограничения
Что МОЖНО делать в shutdown function:
- Логирование в файлы
- Отправка заголовков (если они еще не отправлены)
- Закрытие соединений с БД и файлов
- Отправка email-уведомлений
- Очистка временных файлов
Что НЕЛЬЗЯ делать:
- Выполнять длительные операции (скрипт уже завершается)
- Полагаться на сессии (session handler может быть уже закрыт)
- Использовать некоторые расширения (они могут быть уже выгружены)
6. Комбинирование с другими обработчиками
Полная система обработки ошибок:
// Обычные ошибки -> в исключения
set_error_handler(function($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
// Непойманные исключения
set_exception_handler(function($exception) {
error_log("Uncaught exception: " . $exception->getMessage());
});
// Фатальные ошибки
register_shutdown_function(function() {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
error_log("Shutdown due to: {$error['message']}");
}
});
7. Передача аргументов в shutdown function
$userId = 123;
$action = 'process_data';
register_shutdown_function(function($userId, $action) {
error_log("User $userId completed action: $action");
}, $userId, $action);
8. Множественная регистрация
register_shutdown_function(function() {
echo "First shutdown function\n";
});
register_shutdown_function(function() {
echo "Second shutdown function\n";
});
// Выведет:
// First shutdown function
// Second shutdown function
9. Практические кейсы использования
Гарантированное логирование:
class Logger {
private static $logs = [];
public static function log($message) {
self::$logs[] = $message;
}
public static function registerShutdown() {
register_shutdown_function(function() {
if (!empty(self::$logs)) {
file_put_contents('app.log', implode(PHP_EOL, self::$logs) . PHP_EOL, FILE_APPEND);
}
});
}
}
Logger::registerShutdown();
Logger::log("Важное сообщение");
// Даже при фатальной ошибке сообщение будет записано
Очистка временных данных:
$tempFile = '/tmp/processing_' . uniqid();
register_shutdown_function(function() use ($tempFile) {
if (file_exists($tempFile)) {
unlink($tempFile);
}
});
// Работа с временным файлом...
10. Отладка и тестирование
register_shutdown_function(function() {
$memory = memory_get_peak_usage(true) / 1024 / 1024;
$time = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];
error_log("Memory peak: {$memory}MB, Time: {$time}s");
});
Итог:
register_shutdown_function()
— это механизм “последнего рубежа” выполнения кода в PHP. Его ключевые особенности:
- Выполняется всегда — даже при фатальных ошибках и
exit()
- Не перехватывает ошибки — но позволяет их обнаружить через
error_get_last()
- Полезен для:
- Обработки фатальных ошибок
- Гарантированного освобождения ресурсов
- Финального логирования и очистки
- Мониторинга производительности
- Ограничения — нельзя полагаться на все расширения и сервисы
Это критически важный инструмент для создания отказоустойчивых приложений, особенно в сочетании с set_error_handler()
и set_exception_handler()
.