E_NOTICE? == E_DEBUG, избегая isset() и @с более сложным error_handler
Какие существуют лучшие способы избежать избытка isset()
в логике приложения и сохранить возможность видеть сообщения отладки (E_NOTICE), когда это необходимо?
Презумпция первая: E_NOTICE не является ошибкой, она неверна и должна быть E_DEBUG. Однако, хотя это верно для неустановленных переменных (PHP по-прежнему является языком сценариев), некоторые функции файловой системы и т.д. Бросают их тоже. Поэтому желательно разработать с помощью E_NOTICEs.
Однако не все отладочные уведомления полезны, поэтому это общая (неудачная) идиома PHP для вводит isset()
и @во всей логике приложения. Конечно, существует много допустимых вариантов использования isset/empty, но в целом это кажется сильной синтаксической солью и может фактически препятствовать отладке.
Вот почему я в настоящее время использую букмарклет error_reporting и немой переключатель включения/выключения:
// javascript:(function(){document.cookie=(document.cookie.match(/error_reporting=1/)?'error_reporting=0':'error_reporting=1')})()
if (($_SERVER["REMOTE_ADDR"] == "127.0.0.1")
and $_COOKIE["error_reporting"])
{
error_reporting(E_ALL|E_STRICT);
}
else {/* less */}
Однако это все еще оставляет мне проблему с слишком большим количеством уведомлений для поиска через один раз. В качестве обходного пути я мог бы использовать оператор подавления ошибок @. В отличие от isset() он не полностью убивает параметры отладки, потому что пользовательский обработчик ошибок все равно может получать подавленные E_NOTICE. Таким образом, это может помочь отделить ожидаемые отладочные уведомления от потенциальных проблем.
Но это также неудовлетворительно. Отсюда вопрос. Кто-нибудь использует или знает более сложный обработчик ошибок PHP. Я представляю что-то, что:
- выводит нефильтрованные ошибки/предупреждения/уведомления (с абсолютным позиционированием CSS?)
- и AJAX - не разрешить проверку и подавление на стороне клиента.
- но также сохраняет список фильтров ожидаемых и " одобренных" уведомлений или предупреждений.
Конечно, в какой-то инфраструктуре уже должен быть обработчик ошибок пользователя.
- В основном я заинтересован в управлении предупреждениями/уведомлениями.
- Полное подавление E_NOTICE действительно не требуется.
- E_NOTICES . Только меньше. По умолчанию выделяют те, которые мне могут быть интересны, а не ожидаемые.
- Если я запускаю без параметра order =, ожидается ожидаемое время ожидания. Из-за чего мне не нужно сообщать об этом несколько раз.
- Однако в режиме полной отладки я хочу видеть наличие переменных undefined в присутствии (или более интересного отсутствия) указанных отладочных уведомлений. → Это то, за что я думаю. Избегание isset приводит к неявным заявлениям печати.
- Также понимаем, что это касается случаев, когда удобна обычная семантика обработки форм PHP, а не области приложений, где строгость является обязательной.
О, мой, кто-то, пожалуйста, помогите переписать это. Длительное объяснение не работает.
Ответы
Ответ 1
Хорошо, если вы подождете PHP 7, у вас будет доступ к null coalesce trernary, который, помимо наличия самое крутое имя оператора (я назову своего следующего парня "Null Coalesce" ) позволит вам сделать это:
$var = $some_array[$some_value] ?? "default value";
Что заменяет вездесущий (и уродливый)
$var = isset( $some_array[$some_value] ) ? $some_array[$some_value] : "default_value";
Ответ 2
Можно создать большое приложение PHP, которое никогда не испускает никаких E_NOTICE. Все, что вам нужно сделать, - избегать ситуаций, в которых может быть выпущено Уведомление, подавляющее большинство из которых являются неинициализированными переменными и несуществующими ключами массива. К сожалению, это связано с вашим желанием избежать isset()
- и расширения array_key_exists()
- потому что они предназначены для обработки этой точной проблемы.
В лучшем случае вы можете свести к минимуму их использование путем тщательного построения каркаса. Обычно это означает (например) входной уровень, которому сообщают, какие переменные GET
ожидать, а какие - отсутствующие по умолчанию. Таким образом, код, специфичный для страницы, всегда будет иметь значения для просмотра. Это, в целом, полезный метод, который может быть применен к различным API-интерфейсам. Но я сомневаюсь, должно ли это быть высокоприоритетной задачей дизайна.
В отличие от некоторых других языков, PHP различает не существующую переменную и содержит обычно "пустое" значение (обычно null
). Это, вероятно, артефакт дизайна из более ранней версии, но тем не менее он все еще присутствует, поэтому вы не можете его избежать.
Ответ 3
Я использую isset()
только для переменных $_GET
и $_SERVER
, где данные поступают из вне управления моим приложением. И я использую его в какой-то другой ситуации, когда у меня нет времени писать правильное решение ООП, чтобы избежать его, но я уверен, что его можно избежать в большинстве, если не во всех местах. Например, лучше использовать классы вместо ассоциативных массивов, поэтому вам не нужно проверять наличие ключа массива.
Мои советы:
- Избегайте использования оператора
@
.
- Используйте Xdebug. Во-первых, он печатает легко читаемые и легко заметные сообщения о каждом уведомлении/предупреждении, и он печатает очень полезную трассировку стека на исключениях (вы можете настроить ее для распечатки каждого параметра метода и каждой локальной переменной (
xdebug.collect_params=4
и xdebug.show_local_vars=on
). Во-вторых, он может отключить оператор @
с помощью значения конфигурации xdebug.scream=1
. Вы можете использовать Xdebug для профилирования и для анализа покрытия кода. strong > должен быть на вашей машине разработки.
- Для отладки я также использую FirePHP, потому что он работает с Firebug и может печатать сообщения в Firebug console, поэтому его можно использовать для отладки AJAX.
- С настраиваемым обработчиком ошибок вы можете улавливать и фильтровать любые ошибки и предупреждения, и вы можете записывать их в файл или отображать их с помощью FirePHP, или вы можете использовать, например, jGrowl или Gritter, чтобы их можно было отобразить на веб-странице.
Я использую модифицированную версию примера в руководстве PHP:
<?php
//error_reporting(0);
set_error_handler("errorHandler");
function errorHandler($errno, $errstr, $errfile, $errline)
{
echo "errorHandler()<br />\n";
// filter out getImageSize() function with non existent files (because I'am avoiding using file_exists(), which is a costly operation)
if ( mb_stripos($errstr, 'getimagesize') !== false )
return true;
// filter out filesize() function with non existent files
if ( mb_stripos($errstr, 'filesize') !== false )
return true;
// consoleWriter is my class which sends the messages with FirePHP
if (class_exists('consoleWriter'))
consoleWriter::debug(array('errno'=>$errno, 'errstr'=>$errstr, 'errfile'=>$errfile, 'errline'=>$errline, 'trace'=>debug_backtrace()), "errorHandler");
switch ($errno) {
case E_USER_ERROR:
$out .= "<b>FATAL_ERROR</b> <i>$errno</i> $errstr<br />\n";
$out .= "Fatal error on line $errline in file $errfile";
echo "</script>$out"; // if we were in a script tag, then the print is not visible without this
//writeErrorLog($out);
echo "<pre>";
var_export(debug_backtrace());
echo "</pre>";
exit(1);
break;
case E_USER_WARNING:
$out .= "<b>WARNING</b> <i>$errno</i> $errstr<br />\n";
$out .= "On line $errline in file $errfile<br />\n";
break;
case E_USER_NOTICE:
$out .= "<b>NOTICE</b> <i>$errno</i> $errstr<br />\n";
$out .= "On line $errline in file $errfile<br />\n";
break;
default:
$out .= "<b>Unknown</b> <i>$errno</i> $errstr<br />\n";
$out .= "On line $errline in file $errfile<br />\n";
break;
}
if (!class_exists('consoleWriter'))
echo $out;
//writeErrorLog($out);
//addJGrowlMessage($out);
// Don't execute PHP internal error handler
return true;
}
function testNotice($a)
{
echo $a;
}
testNotice();
Еще один совет не использовать закрывающий тег ?>
в конце файлов только для php, потому что это может вызвать headers already sent
ошибки в конфигурациях, где по умолчанию отключена буферизация вывода.
Ответ 4
попробуйте xdebug
- http://www.xdebug.org/docs/stack_trace
много проверок isset
не вредит u,
на самом деле, он рекомендует объявлять переменные перед использованием
Ответ 5
Я думаю, что лучшая практика - это не трата времени. Это правда, уведомление не является ошибкой, но с правильным объявлением переменной и проверкой ваш код может быть более читабельным и безопасным.
Но не так сложно написать пользовательский обработчик ошибок, при этом debug_backtrace сортирует E_NOTICE (8) с регулярным выражением.
Ответ 6
У меня было подобное желание. Поэтому я начал использовать собственные обработчики ошибок.
http://php.net/manual/en/function.set-error-handler.php
Затем вы можете создать свои собственные фильтры/механизмы для отображения/регистрации ошибок/уведомлений.
Ура!
Ответ 7
PHP определенно нарушен, что делает код менее понятным. "null" означает "undefined" - достаточно просто.
Вот что я делаю, когда сталкиваюсь с этой проблемой, делая код нечитаемым:
/**
* Safely index a possibly incomplete array without a php "undefined index" warning.
* @param <type> $array
* @param <type> $index
* @return <type> null, or the value in the index (possibly null)
*/
function safeindex($array, $index) {
if (!is_array($array)) return null;
return (isset($array[$index])) ? $array[$index] : null;
}
// this might generate a warning
$configMenus = $config['menus'];
// WTF are you talking about!! 16 punctuation marks!!!
$configMenus = (isset($config['menus']) ? $config['menus'] : null;
// First-time awkward, but readible
$configMenus = safeindex($config, 'menus');
Перекрестный ответ здесь. Помогает ли это спам-контролеру?
Ответ 8
Лучшим способом избежать isset()
, на мой взгляд, является определение ваших переменных перед их использованием. Мне не нравится isset()
не столько потому, что это уродливо, а потому, что оно способствует плохой практике программирования.
Что касается самой обработки ошибок, я помещаю всю эту информацию в журналы сервера. Я также использую php -l
в командной строке для синтаксиса проверки программ перед началом работы. Я делаю красивые сообщения для пользователей по умолчанию.
Вы можете заглянуть в одну из различных фреймворков, чтобы убедиться, что любой из них будет работать на вас. Большинство из них, на которые я смотрел, имеют процедуры обработки ошибок, чтобы упростить работу, чем предлагает PHP.
EDIT:
@mario - мой ответ на ваш комментарий становился слишком длинным:-). Я не сторонник определения типов или перехода к каким-то строгим форматам, как Java или C. Я просто выступаю за объявление переменной в контексте, который он использовал. ($foo = null;
- это не то же самое, что оставить переменную пустой).
Я думаю, что это большая проблема с глобальными переменными во многих случаях, особенно супер глобальными для получения данных GET и POST. Я действительно хочу, чтобы PHP сбросил супер-глобалы в пользу класса для получения входных данных. Что-то вроде этого (супер просто, но эй, ты хотел чего-то конкретного::))
<?php
class PostData {
private $data;
public function __construct() {
$this->data = $_POST;
unset($_POST);
}
public function param($name, $value = null) {
if( $value !== null ) {
$this->data[$name] = $value;
}
if( isset( $this->data[$name] ) ) {
return $this->data[$name];
}
return null;
}
}
?>
Включите класс, который вы можете получить и установить POST-данные из метода param()
. Также было бы хорошим способом включить проверку во входные данные. И в качестве бонуса не проверяйте все на isset()
(это уже есть).
Ответ 9
Это уже устаревший ответ, но я изначально использовал гибкого диспетчера журналов, https://github.com/grosser/errorhandler (Не совсем то, что я был ищет IIRC, но, по крайней мере, немного сложнее, чем чередование полного и частичного подавления.)
В любом случае, я использую $_GET->int["input"]
обертку для наиболее распространенных случаев. Это всего лишь тривиальная оболочка ArrayAccess, неявно ловит несуществующие вары, что позволяет легче восстанавливать уведомления. (Только побочный продукт. В первую очередь, для немедленной фильтрации.)
И для другого проекта я даже использую макрос препроцессора [email protected]($var)
, чтобы разрешить включение/выключение или лог-перенаправление в зависимости от параметров сборки.