Предотвращение вывода ошибок трассировки PHP при использовании пользовательского обработчика останова

Мне, должно быть, что-то не хватает в понимании обработки ошибок 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();
}

Ответ 1

Информация о нежелательной ошибке связана с конфигурацией регистрации ошибок (log_errors и error_log) и полностью не зависит от конфигурации display_errors. Конфигурация php.ini по умолчанию регистрирует данные об ошибках до stderr при запуске скриптов из командной строки. Под Apache они отображаются в /etc/httpd/logs/error_log.

Проверьте php_error_cb в main.c источника PHP. В частности, строка 1056 дает понять, что любые сообщения формата "%%% s% s% s on line% d" связаны с конфигурацией регистрации ошибок (информация об ошибке из-за display_errors не будет иметь "PHP:" prefix).

Ответ 2

Несколько возможных решений, отвечая, потому что раздел комментариев злился на меня.

Изменить №3 с помощью решения:

По-видимому, E_ERROR и display_errors не играют хорошо вместе

Вы можете установить error_reporting в E_ALL и ~ E_ERROR, а просто позволить обработчику выключения обрабатывать фатальное (так как это последнее, что нужно назвать так или иначе).

Кроме того, E_ALL не включает E_DEPRECATED до PHP 5.4.0, поэтому, если вы тоже хотите его поймать, используйте ~0 & ~E_ERROR


display_errors могут быть прослушиваемы

Вот суть в том, как вы можете заставить его выплюнуть ошибки, даже если вы сказали это не: https://gist.github.com/1483028

Если вы установите display_errors на 0 через ini_set(), он все равно отобразит Fatal Errors

Хотя display_errors можно установить во время выполнения (с помощью ini_set()), это не повлияет, если script имеет фатальные ошибки. Это связано с тем, что желаемое действие во время выполнения не выполняется.

Кроме того, вы можете отправить его также в stderr, так что это потрясающе.

http://www.php.net/manual/en/errorfunc.configuration.php#ini.display-errors

Изменить 2: Убедитесь, что вы изменили правильный php.ini

Просто подумал об этом и прокомментировал как таковой, но есть более одного файла php.ini. Если вы делаете это в командной строке, вам нужно отредактировать cli one (/etc/php5/cli/php.ini на Ubuntu), а не веб-сайт (/etc/php5/apache2/php. INI)

Думаю, вам просто нужно установить php.ini для отображения display_errors 0.