Мне, должно быть, что-то не хватает в понимании обработки ошибок PHP, в частности, подавления их вывода. Когда возникает фатальная ошибка, я ожидаю, что моя функция обработчика выключения обработает ее изящно и завершит выполнение script. Это работает так, как ожидалось. Однако я не могу помешать PHP выводить информацию о фатальной ошибке.
Мой файл php.ini содержит следующие директивы:
error_reporting = E_ALL | E_STRICT
display_errors = Off
Я установил error_reporting
, чтобы сообщить обо всем, и я использую собственный обработчик ошибок для исключения исключений. Я ожидаю, что display_errors = Off
предотвратит отображение любых сообщений об ошибках.
В любом случае, когда возникает фатальная ошибка, пользовательский обработчик ошибок обходит (поскольку выполнение script выполняется немедленно) и выполняется обработчик завершения работы.
Теперь, на мой упрощенный код:
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'Off');
function shutdown_handler()
{
$err = error_get_last();
$fatal = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR);
if ($err && in_array($err['type'], $fatal)) {
echo "\n\ntest fatal error output\n\n";
}
exit();
}
register_shutdown_function('shutdown_handler');
Чтобы протестировать его, я генерирую фатальную ошибку "Допустимый размер памяти":
// max out available memory
$data = '';
while(true) {
$data .= str_repeat('#', PHP_INT_MAX);
}
Поскольку у меня есть display_errors = Off
, я ожидаю, что это будет производить только следующий вывод (в соответствии с обработчиком выключения):
test fatal error output
Но вместо этого я продолжаю получать:
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2147483648 bytes) in /home/daniel/mydev/php/test0.php on line 24
PHP Stack trace:
PHP 1. {main}() /home/daniel/mydev/php/test0.php:0
PHP 2. str_repeat() /home/daniel/mydev/php/test0.php:24
test fatal error output
Что мне не хватает, что предотвратит вывод этой ошибки?
Заключение
Похоже, как @Cthos отметил, что "E_ERROR и display_errors не играют хорошо вместе".
Это также относится к E_PARSE (и я предполагаю E_CORE_ERROR/E_COMPILE_ERROR, но я не нарушил установку PHP, чтобы проверить его). Я полагаю, что имеет смысл, что PHP заставит трассировку ошибок в STDOUT в этих случаях, потому что если бы вы этого не сделали, вы, возможно, никогда не узнаете, если/почему все идет не так.
Таким образом, решение в этом случае будет:
- Как предложено @Cthos, отключите уведомления E_ERROR в php.ini:
error_reporting = (E_ALL & ~ E_ERROR)
или во время выполнения с помощьюerror_reporting(E_ALL & ~ E_ERROR);
- Обновите обработчик выключения, чтобы проверить, была ли последняя ошибка типа E_ERROR и выполните соответствующие действия, если это так.
Что касается других смертей, таких как E_PARSE, E_CORE_ERROR и т.д., вам просто нужно убедиться, что ваш код верен и что ваш PHP работает. Если вы попытаетесь отключить ошибки E_PARSE и обработать их в своей функции выключения, это не сработает, потому что ошибки синтаксического разбора не позволяют PHP так далеко заходить.
Итак, обновленный/рабочий обработчик завершения выглядит следующим образом:
error_reporting(E_ALL & ~ E_ERROR);
function shutdown_handler()
{
$err = error_get_last();
if ($err && $err['type'] == E_ERROR) {
$msg = 'PHP Fatal Error: '.$err['message'].' in '.$err['file'].
' on line '.$err['line'];
echo $msg, PHP_EOL;
}
exit();
}