Comments 75
Небольшое улучшение по обработке фатальных ошибок:
// clean all buffers
while (ob_get_level()) {
ob_end_clean();
}
>function error_handler
никогда так не делайте. кидайте ErrorException и обрабатывайте его.
никогда так не делайте. кидайте ErrorException и обрабатывайте его.
>echo "{$errors[$errno]}[$errno] $errstr ($errfile на $errline строке)
\n";
так же очень хочется видеть стек вызовов, входные параметры, разную логику в девелоперском и рабочем окружении
\n";
так же очень хочется видеть стек вызовов, входные параметры, разную логику в девелоперском и рабочем окружении
1. Включайте трейс в начале скрипта, получайте стек в обработчике, кто мешает?
2. Ну обьявите окружение, в зависимости от окружения обрабатывайте
Эта статья — не пример использования, а гайд для тех кто желает разобратся. А уж используйте сами как хотите.
2. Ну обьявите окружение, в зависимости от окружения обрабатывайте
Эта статья — не пример использования, а гайд для тех кто желает разобратся. А уж используйте сами как хотите.
Для фатальных ошибок трейс перестанет существовать так как текущий контекст исполнения уничтожается.
Действительно ли отдельная от исключений обработка ошибок имеет смысл? Не слишком ли это все запутано? Не собираются ли разработчики PHP от нее избавляться?
хотят наверное, но не могут. ибо порушится половина сайтов где эти ошибки сейчас просто гасятся собаками или настройками php.ini. обратная совместимость чтоб её. может с выносом всех функций о отдельные неймспейс php и можно будет такое сделать. но сейчас точно нет.
Это вопрос к разработчикам. А пока не избавились иногда без этого всего просто никуда.
Имеет, например, нет смысла бросать исключения в случае E_NOTICE (тем более в случаях E_STRICT или E_DEPRECATED), а сигнализировать об ошибке полезно.
Хм, давно уже не видел людей игнорирующих нотайсы…
Посмотрите на IP.Board (http://community.invisionpower.com/) их даже за ошибки не считают :) но вообще я не говорил что их нужно игнорировать, но вот выкидывать исключения это слишком, ИМХО.
Ну почему в других языках это не «слишком» а вот конкретно в случае пхп становится «слишком»? :)
В каких других языках с динамической типизацией E_NOTICE при пропуске переменной или E_STRICT или тем более E_DEPRECATED выбрасывают исключение или приводит к фатальным ошибкам?
Не совсем понял что вы имеете в виду под «пропуском переменной».
Но если вам так нужен пример к моему коментарию — несуществующий индекс выбросит исключение в питоне, и это нормально.
Но если вам так нужен пример к моему коментарию — несуществующий индекс выбросит исключение в питоне, и это нормально.
> Не совсем понял что вы имеете в виду под «пропуском переменной»
Индекс как в вашем примере или свойство объекта или просто переменная с очепяткой.
> несуществующий индекс выбросит исключение в питоне
Но не выбросит в javascript и это тоже нормально.
PS: критичные ошибки (с E_WARNING) лично мне были бы удобнее в виде исключений.
Индекс как в вашем примере или свойство объекта или просто переменная с очепяткой.
> несуществующий индекс выбросит исключение в питоне
Но не выбросит в javascript и это тоже нормально.
PS: критичные ошибки (с E_WARNING) лично мне были бы удобнее в виде исключений.
Давайте я открою вам глаза…
Ну и контрольный в голову:
<script>
foo={}
if(foo.bar == false) {
alert("You won't see me!");
}
</script>
<?php
Class Foo
{
}
$bar = new Foo();
if($bar->baz == false && $not_defined_var == false)
{
echo "BINGO!";
}
Ну и контрольный в голову:
<script>
try {
if(not_defined_var == false) {
}
} catch (e) {
alert('HAHA!');
}
</script>
Не совсем понятно что именно вы хотели показать этими примерами?
1) undefined в js для неопределенных свойств (вообще никаких предупреждений)
2) особенности приведения типов в PHP (тут хоть нотис есть)
3) необходимость явного объявления в переменных в js
1) undefined в js для неопределенных свойств (вообще никаких предупреждений)
2) особенности приведения типов в PHP (тут хоть нотис есть)
3) необходимость явного объявления в переменных в js
Я хотел сказать что некорректно сравнивать php с js, особенно так как это сделали вы:
Или по вашему поведение типа «не, ну переменная конечно не определена но все равно она равна false потому что я так захотел» это нормально? )
Ну а в последнем примере «просто переменная с очепяткой» выбрасывающая исключение :)
> несуществующий индекс выбросит исключение в питоне
Но не выбросит в javascript и это тоже нормально.
Или по вашему поведение типа «не, ну переменная конечно не определена но все равно она равна false потому что я так захотел» это нормально? )
Ну а в последнем примере «просто переменная с очепяткой» выбрасывающая исключение :)
Как заметили выше, есть не только E_NOTICE, но и E_STRICT и E_DEPRECATED. А ещё есть тонны устаревшего кода, который работает и который никто в здравом уме переписывать не будет. Зато будут обновлять версии пхп, дабы улучшить производительность или закрыть дыры в безопасности.
Главная особенность исключений в том, что они фатальны, если не перехвачены. Поэтому не получится просто взять и поменять старую систему ошибок на новую.
Если интересно, вот мнение расмуса на этот счёт.
Главная особенность исключений в том, что они фатальны, если не перехвачены. Поэтому не получится просто взять и поменять старую систему ошибок на новую.
Если интересно, вот мнение расмуса на этот счёт.
Приезжайте к нам в офис — покажу двух
Так же как и с ошибками, на что генерировать, а на что нет, должно решаться в настройках, по-моему.
Ну, в error_handler вы можете генерировать исключения, более того есть стандартный класс ErrorException, спроектированный специально для этого (в мануале есть пример его использования в этих целях). Несколько строк в начале скрипта и все перехватываемые ошибки будут генерировать исключение, которые можно ловить в месте вызова.
В принципе, наверное, не сложно добавить ini параметр для автоматической генерации, но вряд ли это будет скоро по дефолту.
В принципе, наверное, не сложно добавить ini параметр для автоматической генерации, но вряд ли это будет скоро по дефолту.
Курсовую писали?
нет) хотя соглашусь, что похоже.
на самом деле, хотел сделать небольшой обзор механизма обработки ошибок в кохане (с демонстрацией своего мини-модуля), а как начал копать — не смог остановиться и вот результат ))
хотя от первоначальной идеи не отказываюсь — думаю все же написать обзор, как логическое продолжение этой статьи
на самом деле, хотел сделать небольшой обзор механизма обработки ошибок в кохане (с демонстрацией своего мини-модуля), а как начал копать — не смог остановиться и вот результат ))
хотя от первоначальной идеи не отказываюсь — думаю все же написать обзор, как логическое продолжение этой статьи
про кохану было бы интересно, можно ли ждать поста именно с конахой связанного?
ждать конечно можно, но вот точной датой я вас обрадовать не могу. Кто бы мог подумать, но написание статьи отнимает приличное время…
Для 3.2 писал класс перехвата ошибок. Для ajax-а отправлялся json с ошибкой, для CLI текст. Для обычного запроса — выводилась специальная страница ошибки (в зависимости от типа).
Для версии 3.3 все стало несколько проще… Или сложнее — кому как.
Там теперь можно реализовать метод get_response() в классе *_Exception а в переопределенном Kohana_Exception переопределить статический метод response, который отвечает построение «ответа» ошибки.
Для версии 3.3 все стало несколько проще… Или сложнее — кому как.
Там теперь можно реализовать метод get_response() в классе *_Exception а в переопределенном Kohana_Exception переопределить статический метод response, который отвечает построение «ответа» ошибки.
>при использовании оператора "@" error_reporting() вернет 0
предлагаю при использовании "@" сразу руки отрывать использующему :)
А вообще да, статья полезная для тех кто еще не в курсе, все четко и ясно.
Где вы были 3 года назад когда ну очень надо было а доков почти не было? ))
предлагаю при использовании "@" сразу руки отрывать использующему :)
А вообще да, статья полезная для тех кто еще не в курсе, все четко и ясно.
Где вы были 3 года назад когда ну очень надо было а доков почти не было? ))
По поводу @ согласен, но… бывают ситуации разные.
Вот вам пример:
В случае если вдруг не получилось приконнектиться будет Warning: fsockopen(): unable to connect to
И как же нужно красиво и правильно обрабатывать такую ситуацию без собачки, чтобы ничего лишнего не было в ответе даже на девелоперской машине (т.к. это может, например, попортить json)? Чем тут так плоха собачка @?
Вот вам пример:
$fp = fsockopen($host, $port, $errno, $errstr);
if (!$fp) {
echo "ERROR: $errno - $errstr<br />\n";
} else {
fwrite($fp, "\n");
echo fread($fp, 128);
fclose($fp);
}
В случае если вдруг не получилось приконнектиться будет Warning: fsockopen(): unable to connect to
И как же нужно красиво и правильно обрабатывать такую ситуацию без собачки, чтобы ничего лишнего не было в ответе даже на девелоперской машине (т.к. это может, например, попортить json)? Чем тут так плоха собачка @?
А зачем, извините, использовать безбожно устаревший инструментарий?
Не бывает таких ситуаций:
php.net/manual/en/function.socket-connect.php
php.net/manual/ru/function.stream-socket-client.php
Кстати в случае с последним вам только вызов подключения поменять придется, остальной код не изменится.
Не бывает таких ситуаций:
php.net/manual/en/function.socket-connect.php
php.net/manual/ru/function.stream-socket-client.php
Кстати в случае с последним вам только вызов подключения поменять придется, остальной код не изменится.
Разве эти функции не генерируют warnings?
Как это не странно — нет, не генерируют :)
Обе эти функции еще как генерируют варнинги. Можете сами проверить (только показ варнингов включите).
Вот например: PHP Warning: socket_connect(): unable to connect
И как же быть? Собачка в этом случае всё равно такое зло? Если да, то чем же?
Вот например: PHP Warning: socket_connect(): unable to connect
И как же быть? Собачка в этом случае всё равно такое зло? Если да, то чем же?
Как я уже написал — был не прав. С тем что собака не зло — не соглашусь никогда после того как неделю искал ошибку что притаилась за @session_start написанным каким-то умником в огромном проекте.
О собаках. Я прекрасно понимаю потенциальный вред, который они могут нанести. Но считаю что следует поступать рационально, нежели как гласят какие-то догмы.
Случаи типа
не рассматриваем. Здесь любой мало-мальски опытный программист увидит зло.
Но представим ситуацию: нужно удалить файл, если он есть. Если мы сделаем так:
Есть вероятность, что файл может быть удален другим скриптом, между проверкой и удалением — получим
А так не получим:
Пример выше зависит от того установлен ли обработчик ошибок и того как он работает.
Едем дальше. В последнее время, все чаще прихожу к выводу, что написание
тупо удобнее и лаконичнее, чем
Хотелось бы услышать конструктивную критику приведенных примеров.
Случаи типа
@mysql_connect($host, $user, $pass) or die();
не рассматриваем. Здесь любой мало-мальски опытный программист увидит зло.
Но представим ситуацию: нужно удалить файл, если он есть. Если мы сделаем так:
if (file_exists($file)) unlink($file);
Есть вероятность, что файл может быть удален другим скриптом, между проверкой и удалением — получим
warning
.А так не получим:
@unlink($file);
Пример выше зависит от того установлен ли обработчик ошибок и того как он работает.
Едем дальше. В последнее время, все чаще прихожу к выводу, что написание
$name = @$_GET['name'] ?: $defaultName;
тупо удобнее и лаконичнее, чем
$name = isset($_GET['name']) ? $_GET['name'] : $defaultName;
Хотелось бы услышать конструктивную критику приведенных примеров.
Кстати, да. Это тоже удобно. Спасибо, что напомнили.
А Вы как считаете,
@
хуже чем isset
? Т.е. Вы бы мне руки оторвали за такую запись?Хотелось бы услышать конструктивную критику приведенных примеров.Использование @ для подавления ошибок снижает производительность. Иногда этим можно пренебречь иногда нет.
В php 5.4 над этим поработали.
AndrewStephanoff, не особо в курсе, но разница на простом тесте 0.2-0.3 секунды. PHP 5.4.9.
Спасибо за тест, я сам не проверял — помню по мотивам презентации Змиевского. Видимо раньше было ещё хуже :D
А что за тест такой?
Тест:
Результат PHP 5.3:
Результат PHP 5.4:
Тест:
<?php
$count = 100000;
$t = microtime(1);
for ($i = 0; $i < $count; $i++) {
$zzz = isset($xxx);
}
$t = microtime(1) - $t;
echo "isset: $t<br>";
$t = microtime(1);
for ($i = 0; $i < $count; $i++) {
$zzz = @$xxx;
}
$t = microtime(1) - $t;
echo "@: $t<br>";
Результат PHP 5.3:
isset: 0.0094430446624756
@: 0.080410003662109
Результат PHP 5.4:
isset: 0.0065739154815674
@: 0.059032201766968
Итого, чтобы замедлить скрипт Вам понадобится сто тысяч собак :)
Но, конечно же, эти тесты не говорят ни-че-го. Абсолютно. Медлительность собаки зависит от обработчика ошибок (мы помним, что он запускается всегда). А значит если мы сделаем:
результаты теста очень сильно изменятся :)
Но, конечно же, эти тесты не говорят ни-че-го. Абсолютно. Медлительность собаки зависит от обработчика ошибок (мы помним, что он запускается всегда). А значит если мы сделаем:
set_error_handler(function() {
sleep(1000);
});
результаты теста очень сильно изменятся :)
У вас результат еще хуже, чем у меня :) (значения с @ и без отличаются практически на порядок).
Тест простой:
+ будет райзиться ошибка в кастомном хендлере, если он есть (это дополнительный тормоз)
+ сложнее дебажить
+ ошибки надо исправлять, а не прятать :)
Тест простой:
% cat test1.php
<?php
function x() { }
for ($i = 0; $i < 1000000; $i++) { x(); }
% time php test1.php
php test1.php 1,24s user 0,03s system 69% cpu 1,833 total
% cat test2.php
<?php
function x() { }
for ($i = 0; $i < 1000000; $i++) { @x(); }
% time php test2.php
php test2.php 1,51s user 0,03s system 75% cpu 2,059 total
+ будет райзиться ошибка в кастомном хендлере, если он есть (это дополнительный тормоз)
+ сложнее дебажить
+ ошибки надо исправлять, а не прятать :)
будет райзиться ошибка в кастомном хендлере, если он есть (это дополнительный тормоз)
Это верно. Стоит уточнить, что обработчик будет срабатывать только при ошибке. Т.е. код вида
@foo($bar);
без ошибки будет трансформироваться в
$e = error_reporting(0);
foo($bar);
error_reporting($e);
а с ошибкой в
$e = error_reporting(0);
foo($bar);
error_handler();
error_reporting($e);
сложнее дебажить
В общем случае — да. Но если возникают подозрения, делается простой
grep @
по коду и в обработчике ошибок начинаем логировать/выводить все подряд.ошибки надо исправлять, а не прятать
@ != "прятать", @ == "подавлять вывод"
А исправлять конечно надо.
@ != «прятать», @ == «подавлять вывод»По дефолту (если нет своего хендлера) именно прятать. Поскольку подавленный вывод даже в логе (error_log) не осядет.
делается простой grep @ по кодуДля этого у меня есть xdebug с опцией scream :)
Стоит уточнить, что обработчик будет срабатывать только при ошибке.Верно. Но даже без ошибок мы получаем накладные расходы, которых можно избежать.
подавленный вывод даже в логе (error_log) не осядет.
Кстати, да. Это очень важно.
Для этого у меня есть xdebug с опцией scream
Точно! Это я видел, но еще не пробовал.
даже без ошибок мы получаем накладные расходы
Однозначно.
Я, в принципе, согласен по всем пунктам. Приятно общаться со знающими людьми.
Это все-таки не аргумент, а фуфло.
Особенно при наличии нормальных аргументов.
Особенно при наличии нормальных аргументов.
Есть вероятность, что файл может быть удален другим скриптом, между проверкой и удалением — получим warning.
То есть то что файл удалился не тем скриптом который его должен был удалить — это нормально и у нас все хорошо, да?
Со стороны выглядит примерно так:
1. Какая-то гадость удаляет мои файлы
2.
3. проигнорим мы это дело…
Не выглядит. Файл удаляется этим же скриптом. Обычный Race Condition.
Я Вас понимаю. И не призываю тыкать собаку везде и всюду. Но, Вам тоже не стоит быть таким категоричным. Нужно смотреть зрело, т.е. осознавать к чему это приводит.
Кстати, в Вашей ситуации с сессией, можно было в обработчике ошибок логировать (или выводить) все подряд, тогда бы Вы не тратили столько времени. «Засобаченая» ошибка в любом случае попадает в обработчик.
С тем что собака не зло — не соглашусь никогда после того как неделю искал ошибку что притаилась за @session_start написанным каким-то умником в огромном проекте.
Я Вас понимаю. И не призываю тыкать собаку везде и всюду. Но, Вам тоже не стоит быть таким категоричным. Нужно смотреть зрело, т.е. осознавать к чему это приводит.
Кстати, в Вашей ситуации с сессией, можно было в обработчике ошибок логировать (или выводить) все подряд, тогда бы Вы не тратили столько времени. «Засобаченая» ошибка в любом случае попадает в обработчик.
Критика очень простая.
Типичный похапешник воображает, что ошибка бывает всегда только одна. Та, про которую он, похапешник, случайно узнал.
Мысль о том, что могут встречаться и другие ошибки, никогда не приходит ему в голову.
И по этой причине он начинает считать себя хитрее и умнее всех.
Ровно до тех пор, когда файл невозможно будет удалить не потому что кто-то успел раньше, а потому что нет прав на удаление или имя файла указано неверно.
В итоге наш похапешник имеет неработающее приложение и ни малейшей идеи — почему.
Типичный похапешник воображает, что ошибка бывает всегда только одна. Та, про которую он, похапешник, случайно узнал.
Мысль о том, что могут встречаться и другие ошибки, никогда не приходит ему в голову.
И по этой причине он начинает считать себя хитрее и умнее всех.
Ровно до тех пор, когда файл невозможно будет удалить не потому что кто-то успел раньше, а потому что нет прав на удаление или имя файла указано неверно.
В итоге наш похапешник имеет неработающее приложение и ни малейшей идеи — почему.
Согласен. А что это вы решили написать в прошлое :)?
На эту статью сослался очередной терпила на тостере.
Огорчило, что такие позорные статьи висят на хабре, на тему «самый извращенный способ заменить display_errors=0 в php.ini»
А про собаку уж так — под руку пришлось.
Огорчило, что такие позорные статьи висят на хабре, на тему «самый извращенный способ заменить display_errors=0 в php.ini»
А про собаку уж так — под руку пришлось.
Ого, подняли тему из пепла)
Хотелось бы получить ссылку на вопрос с тостера, чтобы понять контекст вопроса + больше аргументов.
В статье нет призыва использовать собаку или игнорировать ошибки.
Огорчило, что такие позорные статьи висят на хабре, на тему «самый извращенный способ заменить display_errors=0 в php.ini»
Хотелось бы получить ссылку на вопрос с тостера, чтобы понять контекст вопроса + больше аргументов.
В статье нет призыва использовать собаку или игнорировать ошибки.
Забавно — а вот буквально только что сослались на перевод про ODKU :)
С перехватом фатальной ошибки есть небольшой нюанс. Если вы захотите посмотреть стек вызова через debug_print_backtrace(), то увидите, что точка входа в программу — вызов register_shutdown_function(). Чтобы посмотреть нормальный стек вызова, нужно использовать xdebug_get_function_stack() (требует xdebug).
Это точно? Независимо от указанных в set_error_handler классов ошибок? Как-то не обращал внимания, наверное @ крайне редко использую :)
Если вы установили собственную функцию обработки ошибок с помощью set_error_handler(), то она все равно будет вызвана, однако, если внутри этой функции будет вызвана функция error_reporting(), то она вернет 0, если функция, вызвавшая данную ошибку, была подавлена с помощью @.
Упс, там цитата должна была быть :)
да, конечно зависит. если подавляемая ошибка не входит в класс ошибок определенных в set_error_handler(), то функция не будет вызвана.
здесь я хотел заострить внимание на том, что собака не работает как «выключатель» нашего обработчика и этот момент надо учитывать
здесь я хотел заострить внимание на том, что собака не работает как «выключатель» нашего обработчика и этот момент надо учитывать
Sign up to leave a comment.
Ошибки PHP: классификация, примеры, обработка