Я делаю прыжок: мои скрипты 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');
На этот раз я не получаю сообщение об ошибке и даже не вызывает функцию пользовательских ошибок. Сценарий умирает в одной строке.
Кто-нибудь знает, почему и как обойти это?