Web

Как подавить ошибку с помощью оператора @ в PHP

Как вы считаете, допустимо ли использовать оператор «@» для подавления ошибки/предупреждения в 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

Что делает руководитель веб-разработки в рамках своей должности?

Web

Как удалить index.php из пути codeigniter

Web

Как восстановить сериализованную строку, которая была повреждена из-за неправильной длины счетчика байтов

Web

Как получить ID последней обновленной строки в MySQL