set_error_handler Не работает Как я хочу, чтобы он работал

Я делаю прыжок: мои скрипты php будут ВСЕ, изящно!

По крайней мере, это то, на что я надеюсь …

Я не хочу обертывать (практически) каждую строку в try … catch заявлениях, поэтому я считаю, что лучше всего сделать собственный обработчик ошибок для начала моих файлов.

Я тестирую его на странице практики:

function customError($level,$message,$file,$line,$context) { echo "Sorry, an error has occured on line $line.<br />"; echo "The function that caused the error says $message.<br />"; die(); } set_error_handler("customError"); echo($imAFakeVariable); 

Это прекрасно работает, возвращаясь:

Извините, ошибка произошла в строке 17. Функция, вызвавшая ошибку, говорит о неопределенной переменной: imAFakeVariable.

Однако эта настройка не работает для неопределенных функций.

 function customError($level,$message,$file,$line,$context) { echo "Sorry, an error has occured on line $line.<br />"; echo "The function that caused the error says $message.<br />"; die(); } set_error_handler("customError"); imAFakeFunction(); 

Это возвращает:

Неустранимая ошибка: вызов неопределенной функции: imafakefunction () в /Library/WebServer/Documents/experimental/errorhandle.php в строке 17

Почему мой пользовательский обработчик ошибок не обнаруживает неопределенные функции? Есть ли другие проблемы, которые это вызовет?

set_error_handler предназначен для обработки ошибок с кодами: E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE . Это связано с тем, что set_error_handler предназначен для представления сообщений об ошибках, вызванных функцией пользовательской ошибки trigger_error .

Однако я нашел этот комментарий в руководстве, который может вам помочь:

«Следующие типы ошибок не могут быть обработаны с помощью определенной пользователем функции: E_ERROR , E_PARSE , E_CORE_WARNING , E_COMPILE_ERROR , E_COMPILE_WARNING , E_COMPILE_WARNING и большая часть E_STRICT поднятых в файле, где set_error_handler() ."

Это не совсем так. set_error_handler() не может обрабатывать их, но ob_start() может обрабатывать как минимум E_ERROR .

 <?php function error_handler($output) { $error = error_get_last(); $output = ""; foreach ($error as $info => $string) $output .= "{$info}: {$string}\n"; return $output; } ob_start('error_handler'); will_this_undefined_function_raise_an_error(); ?> 

На самом деле, хотя эти ошибки следует сообщать молча в файле, например. Надеюсь, у вас не будет много ошибок E_PARSE в вашем проекте! 🙂

Что касается общего сообщения об ошибках, придерживайтесь исключений (я считаю, что полезно подключить их к моей системе MVC). Вы можете создать довольно универсальное Exception для предоставления опций с помощью кнопок и добавить много описания, чтобы пользователь знал, что не так.

Я думаю, вам нужно также использовать register_shutdown_function

Например:

  register_shutdown_function( array( $this, 'customError' ));. function customError() { $arrStrErrorInfo = error_get_last(); print_r( $arrStrErrorInfo ); } 

Почему мой обработчик ошибок не выполняет функции undefinedd? Есть ли другие проблемы, которые это вызовет?

Полагаю, я бы сказал, что неопределенные функциональные ошибки проходят через другой путь выполнения, чем другие типы ошибок. Возможно, разработчики PHP могли бы рассказать вам больше, кроме того, что я сомневаюсь, что PHP каким-либо образом разработан.

Если вы хотите, чтобы ваши сценарии терпели неудачу, все еще записывая их в стиле PHP, попробуйте поместить всю страницу в функцию и затем вызвать ее в блоке try..catch .

Из документации (выделено мной):

Следующие типы ошибок не могут быть обработаны с помощью определенной пользователем функции: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING и большая часть E_STRICT, поднятых в файле, где вызывается set_error_handler ().

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

PS, если вы загружаете свой собственный обработчик ошибок, вы должны позаботиться о том, чтобы правильно обработать оператор @. Из документации (выделено мной):

Важно помнить, что стандартный обработчик ошибок PHP полностью обойден. Параметры error_reporting () не будут иметь никакого эффекта, и ваш обработчик ошибок будет вызываться независимо – однако вы все еще можете прочитать текущее значение error_reporting и действовать соответствующим образом. Особо следует отметить, что это значение будет равно 0, если оператор, вызвавший ошибку, был добавлен оператором @ error-control.

Очень интересная вещь, которую я обнаружил сегодня, когда сталкивался с подобной проблемой. Если вы используете следующее – он поймает ошибку с помощью вашей специальной функции / метода обработки ошибок:

 ini_set('display_errors', 'Off'); error_reporting(-1); set_error_handler(array("Cmd\Exception\Handler", "getError"), -1 & ~E_NOTICE & ~E_USER_NOTICE); 

Установив 'display_errors' в 'Off', вы можете поймать, чтобы поймать их с помощью обработчика.

Я некоторое время играл с обработкой ошибок, и похоже, что он работает по большей части.

 function fatalHandler() { global $fatalHandlerError, $fatalHandlerTitle; $fatalHandlerError = error_get_last(); if( $fatalHandlerError !== null ) { print($fatalHandlerTitle="{$fatalHandlerTitle} | ".join(" | ", $fatalHandlerError). (preg_match("/memory/i", $fatalHandlerError["message"]) ? " | Mem: limit ".ini_get('memory_limit')." / peak ".round(memory_get_peak_usage(true)/(1024*1024))."M" : "")."\n". "GET: ".var_export($_GET,1)."\n". "POST: ".var_export($_POST,1)."\n". "SESSION: ".var_export($_SESSION,1)."\n". "HEADERS: ".var_export(getallheaders(),1)); } return $fatalHandlerTitle; } function fatalHandlerInit($title="phpError") { global $fatalHandlerError, $fatalHandlerTitle; $fatalHandlerTitle = $title; $fatalHandlerError = error_get_last(); set_error_handler( "fatalHandler" ); } 

Теперь у меня проблема: если память исчерпана, она не сообщает об этом каждый раз. Похоже, это зависит от того, сколько памяти используется. Я сделал сценарий для загрузки большого файла (занимает ~ 6.6M памяти) в бесконечном цикле. Setup1:

 ini_set('memory_limit', '296M'); fatalHandlerInit("testing"); $file[] = file("large file"); // copy paste a bunch of times 

В этом случае я получаю сообщение об ошибке, и оно умирает при загрузке файла на 45.

Setup2 – то же самое, но изменение: ini_set ('memory_limit', '299M');

На этот раз я не получаю сообщение об ошибке и даже не вызывает функцию пользовательских ошибок. Сценарий умирает в одной строке.

Кто-нибудь знает, почему и как обойти это?