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 =, ожидается ожидаемое значение NOTICE. Из-за чего мне не нужно сообщать об этом несколько раз.
  • Однако в режиме полной отладки я хочу видеть наличие неопределенных переменных в присутствии (или, что более интересно, отсутствия) указанных отладочных уведомлений. -> Это то, за что я думаю. Избегание isset вызывает неявные заявления печати.
  • Также понимаем, что это касается случаев, когда удобна простая семантика обработки форм PHP, а не области приложений, где строгость является обязательной.

О, мой, кто-то, пожалуйста, помогите переписать это. Длительное объяснение терпит неудачу.

Ну, если вы подождете PHP 7, у вас будет доступ к тройному оператору с коалесценцией , который, помимо наличия самого крутого имени оператора (я назову своего следующего парня «Null Coalesce»), позволит вам сделать это:

 $var = $some_array[$some_value] ?? "default value"; 

Который заменяет вездесущий (и уродливый)

 $var = isset( $some_array[$some_value] ) ? $some_array[$some_value] : "default_value"; 

Можно разработать большое приложение PHP, которое никогда не испускает никаких E_NOTICE. Все, что вам нужно сделать, – избегать ситуаций, в которых может быть выпущено Уведомление, подавляющее большинство из которых являются неинициализированными переменными и несуществующими ключами массива. К сожалению, это связано с вашим желанием избежать isset() – и расширением array_key_exists() – потому что они предназначены для обработки этой точной проблемы.

В лучшем случае вы можете свести к минимуму их использование путем тщательного построения каркаса. Обычно это означает (например) входной уровень, которому сообщают, какие переменные GET следует ожидать, и к каким недостаткам по умолчанию. Таким образом, код, специфичный для страницы, всегда будет иметь значения для просмотра. Это, в целом, полезный метод, который может быть применен к различным API-интерфейсам. Но я сомневаюсь, должно ли это быть высокоприоритетной целью дизайна.

В отличие от некоторых других языков, PHP различает переменную, не существующую и содержащую обычно «пустое» значение (обычно null ). Это, вероятно, артефакт дизайна из более ранней версии, но тем не менее он все еще присутствует, поэтому вы не можете этого избежать.

Я использую isset() только для переменных $_GET и $_SERVER , где данные поступают вне контроля моего приложения. И я использую его в какой-то другой ситуации, когда у меня нет времени писать правильное решение ООП, чтобы избежать его, но я уверен, что его можно избежать в большинстве, если не во всех местах. Например, лучше использовать классы вместо ассоциативных массивов, так что вам не нужно проверять наличие ключа массива.

Мои советы:

  • Избегайте использования оператора @ .
  • Используйте Xdebug . Во-первых, он печатает легко читаемые и легко заметные сообщения о каждом уведомлении / предупреждении, и он печатает очень полезную трассировку стека на исключениях (вы можете настроить его для распечатки каждого параметра метода и каждой локальной переменной ( xdebug.collect_params=4 и xdebug.show_local_vars=on параметрам конфигурации). Во-вторых, он может отключить оператор @ с xdebug.scream=1 значения конфигурации xdebug.scream=1 Вы можете использовать Xdebug для профилирования и для анализа покрытия кода. Это должно быть на вашей машине разработки.
  • Для отладки я также использую FirePHP , потому что он работает с Firebug и способен печатать сообщения в консоли Firebug , поэтому он также может использоваться для отладки 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 ошибки в конфигурациях, где по умолчанию отключена буферизация вывода.

попробуйте xdebughttp://www.xdebug.org/docs/stack_trace

много проверок isset не наносит вреда u,

на самом деле, он рекомендует объявлять переменные перед использованием

Я думаю, что лучшая практика – это не пустая трата времени. Это правда, уведомление не является ошибкой, но с правильной декларацией переменной и проверкой ваш код может быть более читабельным и безопасным. Но не так сложно написать определяемый пользователем обработчик ошибок, в котором debug_backtrace сортирует E_NOTICE (8) с регулярным выражением.

У меня было такое же желание. Поэтому я начал использовать собственные обработчики ошибок.

http://php.net/manual/en/function.set-error-handler.php

Затем вы можете создать свои собственные фильтры / механизмы для отображения / регистрации ошибок / уведомлений.

Ура!

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'); 

Перекрестный ответ здесь. Помогает ли это спам-контролеру?

Лучший способ избежать 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; } } ?> с <?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() (это уже есть).

Это своего рода устаревший ответ, но я изначально использовал гибкий диспетчер журналов, https://github.com/grosser/errorhandler (Не совсем то, что я искал для IIRC, но, по крайней мере, немного сложнее, чем чередовать полное и частичное подавление.)

Во всяком случае, я тем временем использую $_GET->int["input"] для наиболее распространенных случаев. Это всего лишь тривиальная оболочка ArrayAccess, неявно ловит несуществующие вары, что позволяет легче восстанавливать уведомления. (Только побочный продукт. В первую очередь, для немедленной фильтрации).

И для другого проекта я даже использую макрос препроцессора IFSET@($var) , чтобы разрешить включение / выключение или лог-перенаправление в зависимости от параметров сборки.