Начну с пространного вступления.
Мир PHP очень богат на мифы. Начинающие (и, к сожалению, не только начинающие) программисты зачастую не могут понять истинные причины странного, по их мнению, поведения, не умеют правильно тестировать код, не умеют учиться и изучать. Как следствие, периодически возникают ошибочные представления о работе PHP, которые первым делом попадают туда, куда им никак нельзя попадать — в комментарии к официальной документации PHP. Второе направление атаки — персональные блоги, форумы, статьи — как правило, менее опасное, поскольку не приводит к таким последствиям.
А последствия плачевны. Толковой модерации в комментариях к документации почти нет, живого общения тоже, в результате каждый может написать что-либо о языке, не соответствующее действительности, и эти сведения так и будут висеть годами, пока, возможно, кто-то не напишет ответный комментарий (а в большинстве случаев люди верят подобным комментариям на слово). Так родились на свет десятки мифов и плохих практик программирования, перечислю лишь некоторые:
составление массива строк и последующий implode() быстрее, чем последовательная конкатенация (автор некорректно написал тест производительности);
оператор подавления ошибок очень здорово смотрится перед include (автор плохо понимал, к чему это приводит);
тот же оператор работает ужасно медленно, и лучше его вообще не использовать (по всей видимости, опять виноваты плохой тест производительности и плохое понимание тоже).
Справедливости ради отмечу, что многие комментарии давно потеряли актуальность (вполне возможно, что на момент написания они соответствовали действительности), да и сама документация часто содержит ошибочные примеры и порочные приёмы. В любом случае, все эти проблемы — тема отдельного обсуждения, а сейчас я бы хотел рассмотреть вполне конкретный вопрос.
За время своей работы я заметил, что многие программисты (в том числе достаточно опытные) несколько странно относятся к оператору подавления ошибок. Многие его не любят и стараются избегать, некоторые, наоборот, используют его слишком интенсивно, что в свою очередь может создать больше проблем, чем решить. Прежде чем изложить, как, на мой взгляд, этот оператор должен использоваться правильно, я расскажу, что же он на самом деле делает.
Все мы знаем, что код на PHP иногда порождает ошибки. В одних случаях эти ошибки допускает сам программист, в других случаях ошибки проявляются в нормальном коде как следствие сбойного окружения или некорректной настройки интерпретатора. Некоторые ошибки можно перехватить и обработать, другие нет. Разумеется, в контексте подавления мы можем говорить только о перехватываемых ошибках.Итак, если мы ставим «собаку» перед каким-либо выражением, в операционном массиве виртуальной машины появляются две новые инструкции: BEGIN_SILENCE и END_SILENCE. Код, ошибки которого мы хотим подавить, находится между этими двумя инструкциями и никак не отличается от кода без этих инструкций (для краткости я буду называть этот код «тихим»). Отсюда следует первый важный вывод, который подтверждается тестами: оператор подавления ошибок не замедляет выполнение «тихого» кода. Мнение, что «собака» чутко следит за вверенным ей кодом (потребляя процессорное время) и подавляет ошибки при их возникновении, — ошибочно, работает она принципиально иначе.
Если говорить о содержании инструкций оператора подавления, то делают они одну единственную вещь — устанавливают текущий уровень перехвата ошибок. Соответственно, BEGIN_SILENCE устанавливает этот уровень в ноль (никакие ошибки не перехватываются), а END_SILENCE восстанавливает снятый первой инструкцией уровень обратно. Важно отметить, что в пределах «тихого» кода можно вызвать функцию error_reporting() для установки нового уровня перехвата, либо сделать то же самое с помощью функции ini_set(). И поведение «тихого» кода изменится: он перестанет быть «тихим». Здесь мы можем поинтересоваться, что же будет делать инструкция END_SILENCE, если уровень перехвата был изменён в «тихом» коде. Логика её работы достаточно проста: если текущий уровень равен нулю, восстанавливается тот уровень, который был до выполнения инструкции BEGIN_SILENCE (даже если внутри «тихого» кода устанавливался другой уровень, а потом был сброшен, он не сохранится по выходу из «тихого» кода). Если же уровень остался ненулевой, предыдущий уровень восстановлен не будет. В любом случае, я бы не рекомендовал вручную менять уровень перехвата в разных частях кода, но об этом чуть ниже.
Как быстро работает сам оператор подавления ошибок? По-моему, это вопрос риторический. Две инструкции операционного массива, написанные на C и достаточно простые по своей логике, тормозить не могут. В совокупности с отсутствием задержек при выполнении «тихого» кода мы определяем, что «собака» вовсе не медленная, и с точки зрения производительности бояться её не стоит.
Но скорость выполнения это не единственный критерий выбора. Здесь мы переходим к практикам использования, но для начала разберёмся с теорией. Использование оператора подавления ошибок напрямую связано с Вашей идеологией обработки ошибок. Лично моя идеология весьма проста: любые ошибки всех уровней должны быть перехвачены и обработаны (например, залогированы). Сейчас я не буду углубляться в вопросы наладки механизма обработки ошибок, коротко скажу лишь, что всегда, когда это возможно, я использую собственный обработчик ошибок (устанавливаемый через set_error_handler()), в который попадают ошибки всех перехватываемых типов (уровень перехвата установлен в /-1/ — для всех существующих и будущих уровней) изо всех точек кода. Самый простой способ не умереть под шквалом ошибок в таком случае — писать безошибочный код. Преимуществ у такого подхода масса, и даже с точки зрения производительности это приносит свои плоды: интерпретатор не тратит время на порождение ошибок. Однако, необходимо помнить при установке собственного обработчика ошибок, что он будет запущен и при подавленных ошибках тоже. Поэтому в коде обработчика имеет смысл прерывать обработку, если текущий уровень перехвата равен нулю. Ошибки я с помощью обработчика обычно преобразую в исключения ErrorException, что позволяет вручную перехватывать такие ошибки в коде, либо просто прерывать выполнение кода с помощью собственного обработчика исключений (предварительно залогировав само исключение). В результате мы имеем достаточно «хрупкую», но свободную от ошибок систему.Теперь осталось понять, нужны ли в коде этой системы «собаки». Для этого перечислю несложные правила, которые я посчитал наиболее корректными при работе с оператором подавления.
Первое правило. Оператор подавления ошибок нельзя применять, когда неизвестно точно, какие ошибки могут произойти и по каким причинам Типичный пример — уже упомянутое мной подавление ошибок в подключаемых файлах.
Второе правило. Если есть возможность установить оператор подавления на более низких уровнях кода, нужно это делать. Я даже больше скажу: крайне не рекомендуется ставить «собаку» перед вызовом собственных функций или при создании объектов. Во-первых, код функции может быть не рассчитан на то, что его ошибки будут подавляться. Например, конструкторы объектов часто инициализируют ресурсы или читают данные из внешних источников. Если эти методы сами не будут проверять результат своей работы, Вы можете получить неполноценный объект, дальнейшая работа с которым будет порождать новые ошибки (в том числе фатальные). Даже если сейчас установка «собаки» перед вызовом функции кажется Вам логичной, через полгода, модифицируя эту функцию, Вы уже не вспомните, как она применяется. Во-вторых, как следует из первого правила, устанавливая «собаку» в коде, Вы должны чётко понимать, против каких ошибок она устанавливается, следовательно, Вы можете установить её в более подходящем месте — на более глубоких уровнях кода. В-третьих, Вы можете подавлять ошибки функции в одном месте, но забыть их подавить в другом, где эта же функция будет вызываться. В итоге, лично я взял себе за правило ставить оператор подавления только перед системными функциями или конструкциями, тщательно отслеживая, не попадает ли под действие оператора какой-нибудь самописный метод. Помните это правило и при вызове нескольких функций последовательно в одном выражении — не ставьте оператор подавления перед всем выражением, определите потенциально опасный вызов и поставьте «собаку» перед ним. И да: забудьте про trigger_error(), исключения — наше всё.
Третье правило, вытекающее из второго. Пишите код, держа в уме, что кто-то может поставить перед ним оператор подавления. Не полагайтесь на то, что в нужном месте просто возникнет ошибка и передаст управление Вашему обработчику, который прервёт выполнение основного кода, — всегда проверяйте данные, в целостности которых Вы не уверены.
Четвёртое правило. Если Вы не уверены, в каком окружении будет выполняться Ваш код (к примеру, если Вы пишете публичную библиотеку), старайтесь не использовать «собаку» вовсе. Проблема в том, что пользователь Вашей библиотеки может использовать иную модель обработки ошибок, и его обработчик ошибок будет работать не так, как Вы предполагаете. Если без оператора подавления Вам обойтись трудно, приложите к коду библиотеки свой обработчик ошибок и явно задокументируйте необходимость его использования.
Я перечислил четыре основных правила, ограничивающих применение оператора подавления ошибок в PHP, теперь мы можем рассмотреть ситуации, когда этот оператор можно (и рекомендуется) применять.
Если Вы знаете, что нужный элемент данных (например, ключ массива или переменная) может по каким-то причинам отсутствовать, и это некритично, поскольку Вы можете использовать вместо него значение /null/, — не стесняйтесь, ставьте «собаку» перед обращением к этому элементу. Это короче и понятнее, чем предварительные проверки. Если Вы работаете с файлами, сокетами или другими ресурсами, которые склонны порождать ошибки, и при этом всегда проверяете результат выполнения этих функций, — Вы можете подавлять их ошибки, если Вам неинтересно, что же произошло (так тоже бывает), а вбрасывать вместо этого собственное исключение. В чрезвычайных случаях, когда Вам необходимо в принципе подавить все ошибки, Вы можете их подавить, даже если это идёт в разрез с упомянутыми выше правилами. Например, нельзя вбрасывать исключения в установленном обработчике исключений и нельзя допускать ошибки в установленном обработчике ошибок. Но если Ваш обработчик логирует ошибки, а сам процесс логирования (с помощью функции error_log()) сорвётся, Вы получите такую неприятную ситуацию, и в этом случае допустимо подавить ошибки при вызове error_log(), даже если Вы не знаете причин сбоя.
Как можно заметить, приведённые ситуации встречаются не так уж и часто — но всё же встречаются. И в подобных случаях, если Вы хорошо понимаете, что делаете, оператор подавления ошибок может существенно упростить Ваш код и ускорить его выполнение без повышения каких-либо рисков. Следовательно, Вы можете использовать эту не столь критичную, но полезную возможность языка в противовес тем, кто до сих пор этого не делает. Выбор за Вами!
Я часто вижу, что пишут примерно такой код.
if(isset($arr['a']) && isset($arr['a']['b']) && isset($arr['a']['b']['c'])) {
$v = $arr['a']['b']['c'];
}
else {
$v = null;
}
Но ведь тоже самое, можно написать компактнее, воспользовавшись подавлением ошибки доступа к элементам массива. В случае ошибки будет возвращен null.$v = @$arr['a']['b']['c'];
Почему многие предпочитают первый способ? Религия не позволяет использовать подавление ошибок даже для минимального выражения? Или есть еще какие-то причины?
-
Вопрос задан
-
3081 просмотр
Пригласить эксперта
Не знаю насчет религии, но точно можно было бы обойтись одним isset($arr['a']['b']['c'])
в условии.
если есть ошибка, ее нужно устранить, а не подавить. Подавление ошибок — один из признаков говнокода.
$v = isset($arr['a']['b']['c']) ? $arr['a']['b']['c'] : null;
вот здесь автор предлагает несколько решений, объясняет подводные камни nikic.github.io/2014/01/10/The-case-against-the-if…
а если начать использовать @, то можно потерять действительно нужные ошибки и отладка станет очень тяжелой. Представьте, ничего плохого не произойдёт, если вы одну-единственную переменную в проекте назовёте $a;
Но если таких переменных будет много, код станет невыносимым. Здесь похоже такая же логика.
$arr[$tables[$t][‘name’]][‘rows’][$r][‘cols’][$c][‘format’][‘borders’][‘top’] — это конечно 3.14здец товарищи, но такая конструкция мне никогда не встречалась.
Есть несколько причин:
1) Наглядно видно что происходит в скрипте (есть ключ? нет — ставим default)
2) Упрощает отладку в дальнейшем. «@» скрывает ВСЕ ошибки.
3) Потому, что оператор «@» замедляет выполнение конструкции вида iffset(key) ? key : default в два раза. Даже если ошибки не возникает.
И если уж исходить из редких ситуаций. Представьте насколько замедлится скрипт при прохождении 100000 элементов.
if(isset($arr['a']['b']['c'])) {
$v = $arr['a']['b']['c'];
}
else {
$v = null;
}
$v = isset($arr['a']['b']['c']) ? $arr['a']['b']['c'] : null;
Потому что:
1) сразу понятно что имелось ввиду
2) быстрее
3) ошибки нужно не допускать, а допускать и подавлять сознательно — очень плохой тон, не сразу понятно что вы ожидали получить в результате, это быдлокод, не поддающийся отладке
4) становится похоже на то, что вы вообще не понимаете, что происходит и решили просто убрать отображение ошибки, то что вы там ожидаете null не очевидно чуть менее чем полностью
$arr[$tables[$t]['name']]['rows'][$r]['cols'][$c]['format']['borders']['top']
Страшновато, но программирование не всегда белое и пушистое. Можно либо циклом проверять, либо заняться рефакторингом и сделать более удобную для работы структуру.
-
Показать ещё
Загружается…
23 сент. 2023, в 00:14
40000 руб./за проект
22 сент. 2023, в 23:30
6500 руб./за проект
22 сент. 2023, в 23:29
10000 руб./за проект
Минуточку внимания
В PHP имеется оператор подавления ошибок. В большинстве случаев это нужно для того, чтобы по-своему обработать ошибку. Давайте разберём с Вами оператор подавления ошибок в PHP более подробно.
Оператор подавления ошибок (пишется он так «@«) служит для запрета вывода информации об этих ошибках. Использовать данный оператор можно рядом с тем, что возвращает результат. Например, перед различными функциями, переменными и прочим. Перед служебными конструкциями его нельзя использовать, поскольку они ничего не возвращают. К таким конструкциям относятся циклы, условные операторы, объявления функций и классов.
Теперь пример использования оператора подавления ошибок в PHP:
<?php
$handler = @fopen("my_file.txt", "r");
if (!$handler) echo "Ошибка при открытии файла";
Файла my_file.txt не существует. И если мы уберём «@«, то у нас выведется ошибка, которая нам совсем не нужна, поскольку мы по-своему обрабатываем случай, если файл не открывается или не существует.
Второй очень популярный пример использования «@» при подключении к базе данных:
<?php
$mysqli = @new mysqli("localhost", "root", "123", "mydb");
if ($mysqli->connect_errno) echo "Ошибка при подключении";
В данном случае мы указали неверные данные для подключения к базе данных. Если мы уберём «@«, то PHP нам сразу же выведет ошибку. Однако, мы хотим её обработать сами, поэтому ставим оператор подавления ошибок, а после уже смотрим: возникли ошибки или нет.
Я показал только 2 самых популярных примера использования оператора подавления ошибок в PHP, на практике же есть ещё масса примеров использования данного оператора. Однако, использовать его только для того, чтобы убрать постоянно возникающие ошибки на сайте, не стоит, так как это уже, скорее всего, ошибка в самом коде.
-
Создано 14.06.2013 04:23:49
-
Михаил Русаков
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
-
Кнопка:
Она выглядит вот так:
-
Текстовая ссылка:
Она выглядит вот так: Как создать свой сайт
- BB-код ссылки для форумов (например, можете поставить её в подписи):
PHP подавление ошибок — это способ обработки ошибок в PHP-скрипте, который позволяет скрыть или заменить сообщения об ошибках, чтобы они не отображались пользователю. Это может быть полезно в случаях, когда сообщения об ошибках могут раскрыть информацию о структуре вашего сайта или базы данных.
В PHP существует несколько способов подавления ошибок. Один из них — использование оператора @ перед вызовом функции или выражения, которое может вызвать ошибку. Это выглядит следующим образом:
@функция_которая_может_вызвать_ошибку();
Еще один способ — изменение уровня ошибок на время выполнения скрипта. Это делается с помощью функции error_reporting(). Например, чтобы скрыть все сообщения об ошибках, можно использовать следующий код:
error_reporting(0);
Однако следует помнить, что использование подавления ошибок может сделать код менее безопасным и усложнить отладку ошибок. Поэтому важно использовать его осторожно и только в тех случаях, когда это действительно необходимо.
ООП для начинающих PHP. Исключения (Exceptions)
Автозагрузка классов в PHP
Как легко взломать сайт на PHP — SQL injection
Функции для работы с массивами в PHP. Вся база
Обработка ошибок в PHP7
Почему все ненавидят PHP?
7 ошибок при изучении Php
PSALM, статический анализ PHP проекта
Урок 15. PHP — ООП. Обработчик ошибок (error handler). Исключения (exceptions)
ОБУЧАЮЩИЙ МАРАФОН T7 — ДЕНЬ 2 (14.06.23) — Юридический разбор. Пруфы за 7 месяцев сотрудничества.
Для управления выводом ошибок в
PHP имеется специальный оператор @, называемый
оператором подавления ошибок. Он используется перед выражениями в тех случаях,
когда необходимо предотвратить вывод
сообщений об ошибках, генерируемых данным выражением (см. пример №1). При этом оператор не применяется перед определением функции или класса,
условными конструкциями и т.д. Его разрешается использовать только перед выражениями. Кроме того, нужно иметь в виду, что при использовании
оператора подавления ошибок в случае возникновения критической ошибки дальнейшая работа скрипта будет остановлена без каких-либо уведомлений.
<?php $a; //Выведет предупреждение 'Notice: Undefined variable: a in...' echo $a; //Предупреждение не выводится echo @ $a; //Выведет "Parse error: syntax error, unexpected 'echo' ...", //т.к. перед языковыми конструкциями использовать оператор нельзя @ echo $a; ?>
Пример №1. Использование оператора подавления ошибок
Остальные операторы, перечисленные в таблице операторов,
будут рассмотрены в соответствующих разделах. Что касается побитовых операторов, то они рассматриваются в отдельной статье.