Comments 60
а бы добавил error_reporting:
set_error_handler(create_function('$c, $m, $f, $l', 'if (error_reporting())throw new MyException($m, $c, $f, $l);'), E_ALL);
для обработчки @ собачки и вообще, display errors
set_error_handler(create_function('$c, $m, $f, $l', 'if (error_reporting())throw new MyException($m, $c, $f, $l);'), E_ALL);
для обработчки @ собачки и вообще, display errors
-1
display_errors не обрабатывает собачку, а лишь скрывает ее присутствие.
Сверху есть ссылка, на пост с обсуждением проблем, связанных с употреблением собаки (смешно звучит). В моей статье не обсуждается возможность или невозможность применения собаки, а изыскиваются пути избавления от нее с наибольшей выгодой.
Мне, например, нравится возможность, обрабатывать ошибки, а не решать выводить или не выводить их на экран. Основной плюс в том, что конструктор созданного класса может выполнять любые действия: писать в лог, отсылать на мыло, выводить красивое сообщение об ошибке, да и много чего еще.
Сверху есть ссылка, на пост с обсуждением проблем, связанных с употреблением собаки (смешно звучит). В моей статье не обсуждается возможность или невозможность применения собаки, а изыскиваются пути избавления от нее с наибольшей выгодой.
Мне, например, нравится возможность, обрабатывать ошибки, а не решать выводить или не выводить их на экран. Основной плюс в том, что конструктор созданного класса может выполнять любые действия: писать в лог, отсылать на мыло, выводить красивое сообщение об ошибке, да и много чего еще.
0
Есть проблема — в случае @ перед include/require error_reporting будет нулевой для всех ошибок, возникающих при выполнении подключаемого файла.
0
Неплохо!) Я, как любитель таких вот универсальных штуковин давно хотел придумать себе что-то подобное для обработки ошибок и исключений. Теперь отталкиваться буду от Вашего метода.
0
Не мешало бы добавить в статью об пользовательском обработчике исключений - set_exception_handler(functName), котрый вызывает functName, если исключение не перехвачено.
0
спасибо за интересный пост.
это все хорошо, но php 5 еще дааалеко не на всех хостингах к сожалению.
а вообще рекомендуется писать с включенными
ini_set("display_errors", "1");
error_reporting(E_ALL);
чтобы отсекать все нотисы и ворнинги. фатал ерроры в таких случаях чаще всего будут возникать из за внешних факторов, обусловленных проблемами с базой или хостингом.
это все хорошо, но php 5 еще дааалеко не на всех хостингах к сожалению.
а вообще рекомендуется писать с включенными
ini_set("display_errors", "1");
error_reporting(E_ALL);
чтобы отсекать все нотисы и ворнинги. фатал ерроры в таких случаях чаще всего будут возникать из за внешних факторов, обусловленных проблемами с базой или хостингом.
0
1. если на хостинге php4 - повод задуматься о смене хостера
2. Включенное отображение об ошибках на работающем сайте может быть очень полезно при взломе сайта. Так что лучше либо отключать вовсе, либо логировать.
2. Включенное отображение об ошибках на работающем сайте может быть очень полезно при взломе сайта. Так что лучше либо отключать вовсе, либо логировать.
+2
Я уже видел довольно много даже бесплатных хостингов с PHP5.
Обратите внимание, что поддержка PHP4 закончилась 31 декабря 2007г. Дальше будут только обновления безопасности.
Обратите внимание, что поддержка PHP4 закончилась 31 декабря 2007г. Дальше будут только обновления безопасности.
+2
Мне тоже (как и вашим друзьям-разработчикам) кажется, что это не самый удачный пример использования исключений.
Обычно, рекомендуют использовать исключения только в нештатных ситуациях, ни в коем случае не применяя их для управления логикой исполнения. И этому есть разумные объяснения. Исключения очень хороши во первых тем, что позволяют снять с кода бросающего исключение ответственность по его обработке, давая возможность среагировать на ошибку коду, который знает как это сделать. Исключения так же хороши тем, что в отличие от подхода с возвратом кода ошибок их невозможно игнорировать (это как раз к тому, почему они хороши для обработки нештатных ситуаций). Плюс вы получаете преимущества связанные с уменьшением дублирования и улучшения читаемости кода обработки ошибок.
Если же использовать исключения для организации логики, то в этом они подобны goto, если даже не хуже. Из одного места кода вы вдруг переходите в другое. Повсеместное использование исключений разрушает код. Конечно, грань очень тонкая. Неверные данные, введённые пользователем это штатная или не штатная ситуация? Это зависит от точки зрения разработчика и уровня кода работающего с данными (скажем, на уровне представления неверно введённые данные это нормально, если же вы пытаетесь сохранить объект с этими неверными данными в базу то наверное уже нет.)
В вашем случае без исключений вполне можно было бы обойтись. Было бы вполне достаточно вернуть из функции валидации объект с данными об ошибках. Я не вижу, как в этом конкретном примере полезны исключения.
Обычно, рекомендуют использовать исключения только в нештатных ситуациях, ни в коем случае не применяя их для управления логикой исполнения. И этому есть разумные объяснения. Исключения очень хороши во первых тем, что позволяют снять с кода бросающего исключение ответственность по его обработке, давая возможность среагировать на ошибку коду, который знает как это сделать. Исключения так же хороши тем, что в отличие от подхода с возвратом кода ошибок их невозможно игнорировать (это как раз к тому, почему они хороши для обработки нештатных ситуаций). Плюс вы получаете преимущества связанные с уменьшением дублирования и улучшения читаемости кода обработки ошибок.
Если же использовать исключения для организации логики, то в этом они подобны goto, если даже не хуже. Из одного места кода вы вдруг переходите в другое. Повсеместное использование исключений разрушает код. Конечно, грань очень тонкая. Неверные данные, введённые пользователем это штатная или не штатная ситуация? Это зависит от точки зрения разработчика и уровня кода работающего с данными (скажем, на уровне представления неверно введённые данные это нормально, если же вы пытаетесь сохранить объект с этими неверными данными в базу то наверное уже нет.)
В вашем случае без исключений вполне можно было бы обойтись. Было бы вполне достаточно вернуть из функции валидации объект с данными об ошибках. Я не вижу, как в этом конкретном примере полезны исключения.
+7
Вот поэтому я и написал, что это пример, который не несет особой смысловой нагрузки.
В то же время я указал, что можно использовать разные классы исключений и несколько блоков catch, а если и так не хотите, то можно (даже нужно) определить отдельный класс для исключений приложения в целом и указывать соответствующий тип при обработке в блоке catch.
В то же время я указал, что можно использовать разные классы исключений и несколько блоков catch, а если и так не хотите, то можно (даже нужно) определить отдельный класс для исключений приложения в целом и указывать соответствующий тип при обработке в блоке catch.
* This source code was highlighted with Source Code Highlighter.
- class Application_Exception extends Exception {}
- class Validation_Exception extends Exception {}
- try {
- if ($validationError) {
- throw new Validation_Exception('Validation error');
- }
- if ($applicationError) {
- throw new Application_Exception('Application error');
- }
- }
- catch (Validation_Exception $e) {
- //Обрабатываем только ошибки валидации
- }
В этом случае, если возникает ошибка валидации, то она обрабатывается "на месте", а ошибка приложения проскакивает дальше.
0
пример, не несущий смысловой нагрузки, — это не пример, а сферический конь в вакууме. и если опытным это очевидно, то новички пойдут клепать валидаторы через исключения
0
Ого, тут еще кто-то пишет, через 2 года после публикации.
Во-первых, я уже и не помню, почему привел именно такой пример. Наверное, потому что лень было выдумывать что-то реальное для иллюстрации своей мысли.
Во-вторых, у каждого разработчика должна быть определенная эволюция. Я и сам через 2 года, написал бы уже по-другому где-то, но новичок должен пройти все этапы большого пути, включая быдлокод, чтобы понимать «что такое хорошо, а что такое плохо».
Во-первых, я уже и не помню, почему привел именно такой пример. Наверное, потому что лень было выдумывать что-то реальное для иллюстрации своей мысли.
Во-вторых, у каждого разработчика должна быть определенная эволюция. Я и сам через 2 года, написал бы уже по-другому где-то, но новичок должен пройти все этапы большого пути, включая быдлокод, чтобы понимать «что такое хорошо, а что такое плохо».
0
foreach ($error as $e) {
echo $e.'<br />';
}
==
echo implode('<br />', $error);
echo $e.'<br />';
}
==
echo implode('<br />', $error);
+3
Очень ждал материал по исключениям, спасибо. Ибо до сих пор не понимаю их и интерфейсы еще :)
0
wiki.agiledev.ru/doku.php?id=ooad:exception_using
0
более корректный вариант для обработки значения error_reporting:
function my_error_handler($c, $m, $f, $l) {
if (error_reporting() & $c)throw new MyException($m, $c, $f, $l);
}
set_error_handler('my_error_handler');
function my_error_handler($c, $m, $f, $l) {
if (error_reporting() & $c)throw new MyException($m, $c, $f, $l);
}
set_error_handler('my_error_handler');
0
Тогда еще короче:
function my_error_handler($c, $m, $f, $l) {
throw new MyException($m, $c, $f, $l);
}
set_error_handler('my_error_handler', error_reporting());
* This source code was highlighted with Source Code Highlighter.
0
Итерировать по исключению не есть гуд. Не нагружайте инструмент лишним функционалом. FormValidator - отдельно, FormValidationException - отдельно, с кодом ошибки и сообщением (const FIRST_FIELD_ERROR, const LAST_FIELD_ERROR ....).
Несколько скомканный пример, а в целом хорошо. Исключения - очень хорошая практика ИМХО.
Несколько скомканный пример, а в целом хорошо. Исключения - очень хорошая практика ИМХО.
0
А я для себя просто реализовал перехват ошибок и запись в лог-файл. Если кому интересно - вот этот класс: http://www.phpclasses.org/browse/package/4552.html
0
25. echo 'Not validation error! '.$error->getMessage(); — это на каком языке? :) Ладно еще, если в каком-то тестовом примере такой корявый инглиш, но не в публичных же статьях!
0
UFO just landed and posted this here
validation passed
0
"Не ошибка валидации" писать нельзя даже по-русски: это бред. Это значит "не ошибка", т.е. нет ошибки. Как минимум тогда уж "ошибка не валидации", но это тоже бред. В вашем примере стоило просто написать "другая ошибка" и все было бы понятно.
0
Как-то раз я решил стать "настоящим программистом" (с) и переписать код своей маленькой, но очень милой сердцу cms-ки на эксепшны. Немного погуглив, почитал мысли людей, принципы и подходы которых мне очень близки (не только по исключениям, а вообще - "be simple, we don't need rocket science in code") - Раймонда Чена и Джоэля Спольски:
Exceptions by Joel Spolsky
http://www.joelonsoftware.com/items/2003…
Cleaner, more elegant, and harder to recognize by Raymond Chen
http://blogs.msdn.com/oldnewthing/archiv…
и знаете, проникся. И не стал внедрять исключения, а потратил время на продумывание более ясной архитектуры приложения, рефакторинг, и информативные логи ошибок с бектрейсами.
Хотя у exception-powered подхода есть свои преимущества, безусловно. Просто для меня они пока не перевесили главный недостаток - некоторого ухудшения читабельности и "прямолинейности" кода.
Exceptions by Joel Spolsky
http://www.joelonsoftware.com/items/2003…
Cleaner, more elegant, and harder to recognize by Raymond Chen
http://blogs.msdn.com/oldnewthing/archiv…
и знаете, проникся. И не стал внедрять исключения, а потратил время на продумывание более ясной архитектуры приложения, рефакторинг, и информативные логи ошибок с бектрейсами.
Хотя у exception-powered подхода есть свои преимущества, безусловно. Просто для меня они пока не перевесили главный недостаток - некоторого ухудшения читабельности и "прямолинейности" кода.
0
а вот противоположное мнение, от Ивана Сагалаева, которого тоже очень уважаю:
http://softwaremaniacs.org/blog/2005/05/…
http://softwaremaniacs.org/blog/2005/05/…
0
Странно, а я нашел там не прямо противоположное, а абсолютно такое же мнение...
Хороший пример — это реакция на нехватку памяти. У самого Джоэла притчей во языцех стало то, что нерадивые программисты забывают проверять значение, возвращенное из malloc(). Ну хорошо, проверили мы, что malloc вернул "памяти нет". Что делать? Только отказываться от дальнейшей работы этой функции, что тут другое придумать? Вот исключения и делают это автоматически и надежно, не полагаясь на то, что каждая из цепочки в 50 вызывающих функций не забудет передать наверх каждую ошибку, возникшую в самой глубине менеджера памяти.
0
Ксате интересный пример использования исключений, правда я все таки считаю что не для такого они предназначены (все таки неправильно введеные данные пользователем - это нормальная ситуация), и в реальной жизни применять их в этой ситуации не стоит... Но я бы еще добавил Countable, и строчку if((bool)$e->current()) { заменил бы на if(count($e)) {
0
В целом эксепшны юзать хорошо. Но переиспользовать их вредно.
Два момента в которых вы имхо ошибаетесь:
- Нет смысла заворачивать fatal errors в исключения. Вы хотите отлавливать их в try .. catch и красиво завершать? Красиво завершать и так получится если юзать set_error_handler. Или же греет мысль что скажем "division by zero" вы сможете отлавливать и продолжать далее как будто так и надо? И это вместо того чтобы вставить (когда заметите) проверку делителя до деления? Мрак.
- Нотисы и варнинги заворачивать и подавно глупо, ведь сакральный смысл их в том, что программа в продакшн режиме сможет продолжать работу, паралельно залогав эту ошибку в error_logе (и/или отослав мыло), а девелопер поправит как только сможет, нестрашно.
Один момент в котором вы имхо придете к неэффективному/сложному коду:
- Использование исключений для штатных ситуаций (емэйл невалиден) лишь плодит try .. catch блоки, а следить за ними (если их много) ненамного легче чем за глобальными переменными (если их много).
Два момента в которых вы имхо ошибаетесь:
- Нет смысла заворачивать fatal errors в исключения. Вы хотите отлавливать их в try .. catch и красиво завершать? Красиво завершать и так получится если юзать set_error_handler. Или же греет мысль что скажем "division by zero" вы сможете отлавливать и продолжать далее как будто так и надо? И это вместо того чтобы вставить (когда заметите) проверку делителя до деления? Мрак.
- Нотисы и варнинги заворачивать и подавно глупо, ведь сакральный смысл их в том, что программа в продакшн режиме сможет продолжать работу, паралельно залогав эту ошибку в error_logе (и/или отослав мыло), а девелопер поправит как только сможет, нестрашно.
Один момент в котором вы имхо придете к неэффективному/сложному коду:
- Использование исключений для штатных ситуаций (емэйл невалиден) лишь плодит try .. catch блоки, а следить за ними (если их много) ненамного легче чем за глобальными переменными (если их много).
+1
Нет смысла заворачивать fatal errors в исключения. Вы хотите отлавливать их в try .. catch и красиво завершать? Красиво завершать и так получится если юзать set_error_handler.
set_error_handler установить можно только один раз, а если я хочу в разных модулях обрабатывать ошибки по разному? try...catch блоки как раз дают такую возможность.
Про нотисы я указал, что их можно обработать еще в теле set_error_handler, не генерируя исключение.
Использование исключений для штатных ситуаций (емэйл невалиден) лишь плодит try .. catch блоки, а следить за ними (если их много) ненамного легче чем за глобальными переменными (если их много)
А я ведь не генерировал много try...catch блоков... Я накапливал сообщения об ошибках в теле объекта исключения, а бросал его только один раз, соответственно и обрабатывать его нужно только один раз.
Смысл в том, что для разных типов исключений я бы рекомендовал заводить разные классы, тогда некоторые блоки try...catch будут пропускать исключения наверх - вот и получим необходимую гибкость.
0
try {
validateForm(...)
} catch ($e) {
...
}
не более удобно чем:
if (!validateForm(..., &$errors) {
...
}
А помимо неудобства это, хотя выглядит оопэшно, но нарушает инкапсуляцию: код который использует третью библиотеку будет должен знать имена эксепшнов этой библиотеки. Это конечно если есть эксепшны которые не ловятся внутри библиотеки. Иначе нчего особенного, кроме try ... catch которые не по назначению.
Exception - исключительная ситуация, а не рядовая бизнес логика (как валидация емэйла). Сложно представить когда нужно чтобы преимущества эксепшнов (например эскалация эксепшна вверх) были нужны при обнаружении невалидного емэйла. Если ничего кроме возвращения массива ошибок не нужно, то и не нужен всего-то return.
validateForm(...)
} catch ($e) {
...
}
не более удобно чем:
if (!validateForm(..., &$errors) {
...
}
А помимо неудобства это, хотя выглядит оопэшно, но нарушает инкапсуляцию: код который использует третью библиотеку будет должен знать имена эксепшнов этой библиотеки. Это конечно если есть эксепшны которые не ловятся внутри библиотеки. Иначе нчего особенного, кроме try ... catch которые не по назначению.
Exception - исключительная ситуация, а не рядовая бизнес логика (как валидация емэйла). Сложно представить когда нужно чтобы преимущества эксепшнов (например эскалация эксепшна вверх) были нужны при обнаружении невалидного емэйла. Если ничего кроме возвращения массива ошибок не нужно, то и не нужен всего-то return.
0
UFO just landed and posted this here
А помимо неудобства это, хотя выглядит оопэшно, но нарушает инкапсуляцию: код который использует третью библиотеку будет должен знать имена эксепшнов этой библиотеки.
Если вы используете какую-то библиотеку, то вы, во-первых, должны прочитать API и вам желательно знать имена классов, в нее входящих.
Во-вторых, все классы исключений наследуются от Exception, поэтому если вы не хотите учить имена классов можете просто писать catch(Exception $e).
Как это нарушает инкапсуляцию я вообще не понял... Вы же не выносите код класса за его пределы. Все внутриклассовые ошибки обрабатываются в классе, а ошибки связанные с неправильными параметрами, переданными извне должны генерировать исключение. Лично я тут проблемы не вижу.
0
Насчет первого момента, Fatal Error-ы в пыхе не перехватываются. Нет, конечно перехватить их можно, но... это делается через такую жопу, что это никому и ненужно.
Насчет варнингов в пхп все очень тонко. К примеру по варнингу от mysql_connect, можно выкидывать эксепшн - потому, как варнинг нам сообщит о том, что мы не смогли приконнектица к бд, в том же foreach-е если он будет выкидываца - тоже будет хорошо, потому как сразу заставит посмотреть почему же у нас иногда не те данные имеюца (и такое поведение имхо хорошо и для варнингов с киданием заголовков и кук)... но вот в случае с DOMDocument::loadHTML - такое поведение будет неочень хорошо, потому как он же html нормально распарсит, но кинет варинг, а использовать @ или пустой catch - не очень красиво.
Насчет варнингов в пхп все очень тонко. К примеру по варнингу от mysql_connect, можно выкидывать эксепшн - потому, как варнинг нам сообщит о том, что мы не смогли приконнектица к бд, в том же foreach-е если он будет выкидываца - тоже будет хорошо, потому как сразу заставит посмотреть почему же у нас иногда не те данные имеюца (и такое поведение имхо хорошо и для варнингов с киданием заголовков и кук)... но вот в случае с DOMDocument::loadHTML - такое поведение будет неочень хорошо, потому как он же html нормально распарсит, но кинет варинг, а использовать @ или пустой catch - не очень красиво.
0
> К примеру по варнингу от mysql_connect, можно выкидывать эксепшн.
Кидать эксепшн здесь нужно, зачем только для этого перехватывать варнинги
Кидать эксепшн здесь нужно, зачем только для этого перехватывать варнинги
0
Да, насчет Fatal Error, это я протупил, признаю. Почему-то показалось, что такие ошибки, как Division By Zero должны быть Fatal Error...
0
А можно как то вывести дерево функции в порядке их вызова? То есть ошибка была в функции A() которая была вызвана из функции B() которая была вызвана из функции C(). В standalone языках обычно это дебагер сразу показывает + показывает что было передано в параметрах функции. Есть что то такое в php?
0
Довольно просто и функционально, такой ООПшный способ навешивания обработчика мне понравился. Но соглашусь с писавшими выше, что валидатор форм лучше делать отдельно.
0
Простите за «небольшой» некропостинг, но поскольку статья на втором месте в яндексе, то хотелось бы указать небольшой АПДЕЙТ:
Уже довольно давно существует класс ErrorException, так что идея с MyException давно реализована в ядре пхп, и свой велосипед не нужен. Ну и с валидатором тоже конечно кошмарно, но вы это сами указали.
ПС: я понимаю что 8 лет прошло, просто статья по прежнему в топе)
Уже довольно давно существует класс ErrorException, так что идея с MyException давно реализована в ядре пхп, и свой велосипед не нужен. Ну и с валидатором тоже конечно кошмарно, но вы это сами указали.
ПС: я понимаю что 8 лет прошло, просто статья по прежнему в топе)
0
Лол, не знал, что статья в топе. Может, стоит закрыть?
0
Sign up to leave a comment.
Обработка ошибок и исключений в PHP