Подавление ошибок php
Некоторое время назад мне сделали замечание, что использовать @ — «плохая привычка». На предложение доказать, что это именно так, я получил ссылку на Хабр, со статьей про управление ошибками.
Окей, наконец-то я узнал, как именно ими управлять, но чем же плоха привычка подавлять сообщения об ошибках, если ты знаешь, что делаешь?
На мой взгляд, плохого здесь нет и быть не может. Применение @ — это такое же управление ошибками, как и функция error_reporting() или директива в php.ini.
Однако, детальный разбор показал несколько иное.
Я не гуру php, а обычный самоучка, который постигает тонкости программирования исключительно чтением несложных книг и гуглением. Поэтому, теория работы с ошибками в моём изложении крайне проста.
Php — сценарный язык, с динамической типизацией. Это означает, что он компилируется на лету. То есть, вы пишите скрипт, запускаете его в браузере и программа php на лету выполняет ваши команды. В процессе выполнения могут возникать ошибки, и вы можете указать, как именно их обрабатывать.
При своём запуске php смотрит в конфигурационный файл, обычно php.ini, который среди прочего содержит и директиву обработки ошибок, это error_reporting.
В комментариях к этой директиве содержится описание уровней обработки ошибок, приведу его полностью:
По большому счету можно выделить 4 типа ошибок:
E_FATAL — ошибка ужасна, скрипт не может продолжать работу.
E_ERROR — ошибка серьезная, но работать можно, скорее всего, неправильно.
E_WARNING — предупреждение, что ты ленивый программист и не пользуешься IDE. на работу не особо влияет, хотя и может порушить логику приложения.
E_NOTICE — уведомление, что ты не объявил переменную, или обратился к несуществующему элементу массива. Лично я вообще не считаю это ошибокой, ибо поломать логику работы приложения она не может.
Конечно, есть и предупреждения об использовании устаревших функций, и ошибки совместимости, но в целом — их можно отнести к 4м этим типам.
У кого сейчас кровь пошла носом — прочитайте 5й абзац про то, что я самоучка, объясняю как могу. На данный момент нам важно понять вот что: есть ошибки, которые влияют на ход работы, и есть — которые не влияют.
Итак, давайте определим наш дефолтный код, на котором будем проверять теорию:
Этот код отрабатывает у меня за 2.2096891403198. Хороший, правильный код, без ошибок и уведомлений, миллион итераций проходит за 2.2 сек.
А теперь код, который будет обращаться к несуществующему элемента массива, с отключенными уведомлениями:
Этот плохой, нехороший код со спрятанными ошибками выполняется за 1.8394958972931. Да, он быстрее, ибо не проверяет наличие ключа в массиве.
Обратите внимание: я подавил возможные уведомления, указав error_reporting(0) и плохой код работает быстрее. Но я сжульничал.
В моем примере используется array_key_exists(), который, как мне недавно доказал Евгений Борисов, гораздо медленнее обычного isset().
А вот что будет, если немного изменить наш цикл:
И вот, первый серьёзный вывод: проверка ключа массива может работать медленнее, чем подавление ошибок. То есть, 100% правильный код не гарантирует скорости, сам по себе.
Второй серьёзный вывод: обращение к несуществующему элементу массива тормозит работу скрипта. Не подавление ошибок, а обращение к несуществующему элементу.
А теперь финальный тест — подавление ошибки через @.
Однако, наш неправильный код работает наравне с правильным, который использует array_key_exists().
Не нужно обращаться к несуществующим эелемнтам массива и переменным. Вообще, ошибок быть не должно, они тормозят работу. Правильный код не только приятен сам по себе, но и быстрее работает.
И вот ответ на вопрос: плохо ли подавлять ошибки php? После проведённых тестов ответ однозначен: да, плохо. Не люблю признавать свою неправоту, но так и есть. Код с ошибками работает медленнее и подавлять его через @ — не хорошо.
Отсюда логично заключить, что ровно так же не хорошо и подавление ошибок через error_reporting(). И конечно, указание в php.ini E_ALL & ~E_NOTICE — тоже плохо.
Вообще, любой код с ошибками хуже, чем без таковых. Да, ребята, я потратил несколько часов, чтобы доказать это. Я — кэп.
Но, в отличии от моих оппонентов, теперь я точно знаю, почему наличие ошибок (и их подавление) — плохо. Надеюсь, это еще кому-то поможет определиться со своим отношением к правильному коду.
Кстати говоря, с тех пор как я начал использовать PhpStorm, количество таких глупых ошибок резко сократилось. Если кто не читал — вот заметка про работу с этой прекрасной IDE (требуется подписка).
Окей, наконец-то я узнал, как именно ими управлять, но чем же плоха привычка подавлять сообщения об ошибках, если ты знаешь, что делаешь?
На мой взгляд, плохого здесь нет и быть не может. Применение @ — это такое же управление ошибками, как и функция error_reporting() или директива в php.ini.
Однако, детальный разбор показал несколько иное.
Немного теории
Я не гуру php, а обычный самоучка, который постигает тонкости программирования исключительно чтением несложных книг и гуглением. Поэтому, теория работы с ошибками в моём изложении крайне проста.
Php — сценарный язык, с динамической типизацией. Это означает, что он компилируется на лету. То есть, вы пишите скрипт, запускаете его в браузере и программа php на лету выполняет ваши команды. В процессе выполнения могут возникать ошибки, и вы можете указать, как именно их обрабатывать.
При своём запуске php смотрит в конфигурационный файл, обычно php.ini, который среди прочего содержит и директиву обработки ошибок, это error_reporting.
В комментариях к этой директиве содержится описание уровней обработки ошибок, приведу его полностью:
; Error Level Constants: ; E_ALL - All errors and warnings (includes E_STRICT as of PHP 6.0.0) ; E_ERROR - fatal run-time errors ; E_RECOVERABLE_ERROR - almost fatal run-time errors ; E_WARNING - run-time warnings (non-fatal errors) ; E_PARSE - compile-time parse errors ; E_NOTICE - run-time notices (these are warnings which often result from a bug in your code, but it's possible that it was intentional (e.g., using an uninitialized variable and relying on the fact it's automatically initialized to an empty string) ; E_STRICT - run-time notices, enable to have PHP suggest changes to your code which will ensure the best interoperability and forward compatibility of your code ; E_CORE_ERROR - fatal errors that occur during PHP's initial startup ; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's initial startup ; E_COMPILE_ERROR - fatal compile-time errors ; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) ; E_USER_ERROR - user-generated error message ; E_USER_WARNING - user-generated warning message ; E_USER_NOTICE - user-generated notice message ; E_DEPRECATED - warn about code that will not work in future versions of PHP ; E_USER_DEPRECATED - user-generated deprecation warningsОчевидно, что в зависимости от ваших потребностей, вы можете установить любой уровень обработки ошибок: отключить их все, выводить только предупреждения, уведомления и т.д.
Немного про ошибки
По большому счету можно выделить 4 типа ошибок:
E_FATAL — ошибка ужасна, скрипт не может продолжать работу.
E_ERROR — ошибка серьезная, но работать можно, скорее всего, неправильно.
E_WARNING — предупреждение, что ты ленивый программист и не пользуешься IDE. на работу не особо влияет, хотя и может порушить логику приложения.
E_NOTICE — уведомление, что ты не объявил переменную, или обратился к несуществующему элементу массива. Лично я вообще не считаю это ошибокой, ибо поломать логику работы приложения она не может.
Конечно, есть и предупреждения об использовании устаревших функций, и ошибки совместимости, но в целом — их можно отнести к 4м этим типам.
У кого сейчас кровь пошла носом — прочитайте 5й абзац про то, что я самоучка, объясняю как могу. На данный момент нам важно понять вот что: есть ошибки, которые влияют на ход работы, и есть — которые не влияют.
Немного практики
Итак, давайте определим наш дефолтный код, на котором будем проверять теорию:
error_reporting(-1); // вывод всех ошибок
$time = microtime(true);
$array = array();
for ($i = 0; $i < 1000000; $i++) {
$key = rand();
if (array_key_exists($key, $array)) {
$array[$key] += 1;}
else {
$array[$key] = 1;
}
}
echo microtime(true) - $time;
Здесь мы обращаемся к случайному ключу массива, проверяем его наличие и, если он есть, прибавляем единичку, а если нет — просто объявляем элемент массива.Этот код отрабатывает у меня за 2.2096891403198. Хороший, правильный код, без ошибок и уведомлений, миллион итераций проходит за 2.2 сек.
А теперь код, который будет обращаться к несуществующему элемента массива, с отключенными уведомлениями:
error_reporting(0); // все ошибки скрыты
$time = microtime(true);
$array = array();
for ($i = 0; $i < 1000000; $i++) {
$key = rand();
$array[$key] += 1;
}
echo microtime(true) - $time;
Этот код гарантированно генерирует E_NOTICE при обращении к несуществующему элементу массива, но я заранее их спрятал функцией error_reporting(0).Этот плохой, нехороший код со спрятанными ошибками выполняется за 1.8394958972931. Да, он быстрее, ибо не проверяет наличие ключа в массиве.
Обратите внимание: я подавил возможные уведомления, указав error_reporting(0) и плохой код работает быстрее. Но я сжульничал.
А теперь серьезно
В моем примере используется array_key_exists(), который, как мне недавно доказал Евгений Борисов, гораздо медленнее обычного isset().
А вот что будет, если немного изменить наш цикл:
error_reporting(-1);
$time = microtime(true);
$array = array();
for ($i = 0; $i < 1000000; $i++) {
$key = rand();
if (isset($array[$key])) {
$array[$key] += 1;}
else {
$array[$key] = 1;
}
}
echo microtime(true) - $time;
Этот код выполняется за 1.3799779415131. Он быстрее чуть ли не в 2 раза, чем c array_key_exists() и работает точно так же.И вот, первый серьёзный вывод: проверка ключа массива может работать медленнее, чем подавление ошибок. То есть, 100% правильный код не гарантирует скорости, сам по себе.
Второй серьёзный вывод: обращение к несуществующему элементу массива тормозит работу скрипта. Не подавление ошибок, а обращение к несуществующему элементу.
А теперь финальный тест — подавление ошибки через @.
$time = microtime(true);
$array = array();
for ($i = 0; $i < 1000000; $i++) {
@$array[$key] += 1; // подавляем E_NOTICE
}
echo microtime(true) - $time;
И вот этот код работает уже за 2.2371110916138. То есть, медленнее чем правильный код с isset() и медленнее, чем отключение ошибок заранее. И дело тут не в том, что подавление ошибок происходит в цикле, @ тормозит само по себе, даже если его указывать с безошибочным кодом. @ тормозит работу, без вариантов.Однако, наш неправильный код работает наравне с правильным, который использует array_key_exists().
Выводы
Не нужно обращаться к несуществующим эелемнтам массива и переменным. Вообще, ошибок быть не должно, они тормозят работу. Правильный код не только приятен сам по себе, но и быстрее работает.
И вот ответ на вопрос: плохо ли подавлять ошибки php? После проведённых тестов ответ однозначен: да, плохо. Не люблю признавать свою неправоту, но так и есть. Код с ошибками работает медленнее и подавлять его через @ — не хорошо.
Отсюда логично заключить, что ровно так же не хорошо и подавление ошибок через error_reporting(). И конечно, указание в php.ini E_ALL & ~E_NOTICE — тоже плохо.
Вообще, любой код с ошибками хуже, чем без таковых. Да, ребята, я потратил несколько часов, чтобы доказать это. Я — кэп.
Но, в отличии от моих оппонентов, теперь я точно знаю, почему наличие ошибок (и их подавление) — плохо. Надеюсь, это еще кому-то поможет определиться со своим отношением к правильному коду.
Кстати говоря, с тех пор как я начал использовать PhpStorm, количество таких глупых ошибок резко сократилось. Если кто не читал — вот заметка про работу с этой прекрасной IDE (требуется подписка).
Комментарии: 6
Это сообщение было удалено
Коля, ты забанен за то, что не умеешь нормально вести диалог и доказывать свою точку зрения.
Делать себе замечания я умею и сам.
Делать себе замечания я умею и сам.
По-моему программистов не самоучек быть не может :-)
Спасибо за работу!
Спасибо за работу!
Это сообщение было удалено
Такое использование использование символа "@" мне нравится больше (:
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.