Как вы считаете, допустимо ли использовать оператор «@» для подавления ошибки/предупреждения в PHP и в то же время обрабатывать ошибку?
Если да, то при каких обстоятельствах вы бы это сделали?
Примеры кода приветствуются.
Примечание для отвечающих. Я не стремлюсь отключить информирование об ошибках, но общепринятая практика заключается в том, чтобы использовать, например:
@fopen($file);
и затем проверить результат, но, возможно, также сделать следующее:
if (file_exists($file)) {
fopen($file);
} else {
die('File not found');
}
или что-то подобное.
Я полагаю, вопрос в том, есть ли где-нибудь место, где «@» ДОЛЖНО использоваться для подавления ошибки, которая НЕ МОЖЕТ быть обработана любым другим способом?
Ответ 1
Примечание: Я понимаю, что 99% разработчиков PHP используют оператор подавления ошибок (я был одним из них), поэтому я ожидаю, что любой разработчик PHP, который увидит это, не согласится с данным утверждением.
Как вы считаете, правомерно ли использовать оператор «@» для подавления ошибки/предупреждения в PHP, в то время как вы можете обрабатывать ошибку?
Короткий ответ:
Нет!
Более длинный и правильный ответ:
Я не знаю, так как не знаю всего, но пока я не сталкивался с ситуацией, когда это было бы хорошим решением.
Почему это плохое решение:
За 7 лет использования PHP я сталкивался с большими проблемами отладки, вызванными оператором подавления ошибок, и ни разу не сталкивался с ситуацией, когда это было бы неизбежно.
Проблема в том, что часть кода, для которой вы подавляете ошибки, может в настоящее время вызывать только ту ошибку, которую вы имеете; однако когда вы измените код, на который опирается подавляемая строка, или среду, в которой она работает, то есть все шансы, что строка попытается вывести совершенно другую ошибку, а не ту, которую вы пытались игнорировать.
Мне понадобилось много лет, чтобы понять, сколько времени я терял каждые пару месяцев из-за подавленных ошибок. Чаще всего (но не исключительно) это происходило после установки стороннего скрипта/приложения/библиотеки, которая была свободна от ошибок в среде разработчиков, но не в моей из-за разницы в конфигурации php или сервера, или отсутствующей зависимости, которая обычно выводила ошибку, немедленно предупреждая о проблеме, но не тогда, когда разработчик добавлял волшебный «@».
Альтернативы (в зависимости от ситуации и желаемого результата):
Обрабатывать фактическую ошибку, о которой вы знаете, так что если часть кода приведет к определенной ошибке, то она не будет запущена в этой конкретной ситуации. Но я думаю, что вы поняли эту часть, и вас просто беспокоило то, что конечные пользователи увидят ошибки, и именно это я сейчас рассмотрю.
Для обычных ошибок вы можете настроить обработчик ошибок так, чтобы они выводились так, как вы хотите, когда вы просматриваете страницу, но были скрыты от конечных пользователей и регистрировались, чтобы вы знали, какие ошибки вызывают ваши пользователи.
Для фатальных ошибок установите display_errors в off (обработчик ошибок все равно будет срабатывать) в вашем php.ini и включите логирование ошибок. Если у вас есть сервер разработки, а также рабочий сервер (что я рекомендую), то этот шаг не нужен на сервере разработки, так что вы сможете отлаживать фатальные ошибки, не прибегая к просмотру файла журнала ошибок. Есть даже трюк с использованием функции shutdown для отправки большого количества фатальных ошибок в ваш обработчик ошибок.
В итоге:
Пожалуйста, избегайте его применения. Возможно, для этого есть веская причина, но я пока не видел ни одной, поэтому до этого дня я считаю, что оператор подавления ошибок (@) недопустим.
Ответ 2
Если вы не хотите, чтобы при использовании функций типа fopen() выдавалось предупреждение, вы можете подавить ошибку, используя исключения:
try {
if (($fp = @fopen($filename, "r")) == false) {
throw new Exception;
} else {
do_file_stuff();
}
} catch (Exception $e) {
handle_exception();
}
Ответ 3
Я НИКОГДА не позволяю себе использовать «@»... и точка.
Когда я обнаруживаю использование «@» в коде, я добавляю комментарии, чтобы сделать это очевидным, как в месте использования, так и в докблоке вокруг функции, где она используется. Меня также напрягает использование отладки из-за такого рода подавления ошибок, и я надеюсь облегчить задачу следующим людям, подчеркивая его использование, когда я его обнаруживаю.
В тех случаях, когда я хочу, чтобы мой собственный код выбрасывал исключение при возникновении ошибки в собственной функции PHP, и использование «@» кажется простым способом, я вместо этого делаю что-то другое, что дает тот же результат, но (опять же) бросается в глаза в коде:
$orig = error_reporting(); // фиксируем исходный уровень ошибок
error_reporting(0); // подавление всех ошибок
$result = native_func(); // ожидается, что при ошибке native_func() вернет FALSE
error_reporting($orig); // восстановить первоначальный уровень сообщений об ошибках
if (false === $result) { throw new Exception('native_func() failed'); }
Это дает гораздо больше кода, чем просто написание следующего выражения:
$result = @native_func();
Ответ 4
Большинство людей не понимают смысла сообщения об ошибке.
Они думают, что сообщения об ошибках все одинаковые и гласят: «Что-то пошло не так!».
А ведь это самая важная часть сообщения об ошибке — не просто факт его появления, а его смысл. Оно может сказать вам, что именно идет не так. Сообщения об ошибках предназначены для помощи, а не для того, чтобы донимать вас проблемой «как это скрыть?». Это одно из самых больших заблуждений в мире веб-программирования для новичков.
Таким образом, вместо того, чтобы убирать сообщение об ошибке, нужно читать то, что в нем написано. У него не только одно значение — «файл не найден». Это могут быть тысячи различных ошибок: отказ в разрешении, ограничение режима сохранения, ограничение open_basedir и т. д. и т. п. Каждая из них требует соответствующих действий. Но если вы будете подавлять ошибки оператором «@», вы никогда не узнаете, что произошло!
Обработка ошибок предназначена для пользователя. Здесь достаточно показать: «что-то случилось». В то время как сообщение об ошибках предназначено для программиста, которому крайне необходимо знать, что именно произошло.
Поэтому никогда не подавляйте вывод ошибочных сообщений. Как регистрируйте их для программиста, так и обрабатывайте их для пользователя.
Ответ 5
Некоторые функции в PHP выдают E_NOTICE (например, функция unserialize).
Возможный способ перехватить эту ошибку (для PHP версий 7+) — преобразовать все выдаваемые ошибки в исключения и не позволять им выдавать E_NOTICE. Мы можем изменить обработчик ошибок исключений следующим образом:
function exception_error_handler($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('exception_error_handler');
try {
unserialize('foo');
} catch(\Exception $e) {
// ... выбросит исключение здесь
}
Ответ 6
Сегодня я столкнулся с проблемой, которая является хорошим примером того, когда нужно хотя бы временно использовать оператор «@».
Я обнаружил информацию о входе в систему (имя пользователя и пароль в виде обычного текста), записанную в журнал ошибок.
Вот немного больше информации об этой проблеме.
Логика входа в систему находится в отдельном классе, потому что система должна предлагать различные механизмы входа. Из-за проблем с переносом сервера произошла ошибка. Эта ошибка сбрасывала всю трассировку в журнал ошибок, включая информацию о пароле! Один из методов ожидал имя пользователя и пароль в качестве параметров, поэтому трассировка исправно записывала все в журнал ошибок.
Долгосрочным исправлением здесь является рефакторинг указанного класса вместо использования имени пользователя и пароля в качестве двух параметров, например, использование одного параметра массива, содержащего эти два значения (в таких случаях trace будет писать Array для этих параметров). Есть и другие способы решения этой проблемы, но это уже совсем другой вопрос.
В любом случае сообщения трассировки полезны, но в данном случае они были откровенно вредны.
Урок я усвоил, как только заметил этот трассировочный вывод: Иногда подавление сообщения об ошибке на время является полезной временной мерой, чтобы избежать дальнейшего вреда.
На мой взгляд, я не считаю, что это случай плохого дизайна класса. Сама ошибка была вызвана PDOException (проблема с меткой времени при переходе с MySQL 5.6 на 5.7), который просто отправлял все данные PHP в журнал ошибок.
Web