За последние 24 часа нас посетили 22482 программиста и 1188 роботов. Сейчас ищут 698 программистов ...

"красивый" вывод исключений и ошибок.

Тема в разделе "Прочие вопросы по PHP", создана пользователем Koc, 18 апр 2009.

  1. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Проверка формы не показ списка - выполняется относительно просмотра данных оно редко и там есть смысл использовать исключения и не парить собственный мозг насчёт скорости.
    Я сказал © Последний из Могикан. Артур Конан Дойль.
     
  2. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    2Sergey89
    а теперь сравни
    PHP:
    1.  <?php
    2.  // ...
    3.     try{
    4.             MailService::create()
    5.                 ->setTo($form->getValue('email')) // вот тут так и так выскочит ошибка, зачем еще раз это- же самое проверять в валидэйте. лишнюю работу делать хачешь?
    6.                 ->setSubject('Hello');
    7.                 ->send(); // если там не выскочит, то тут уж по-любому
    8.     }
    9.     catch(ServiceException $e ){
    10.         //обработка исключительной ситуации
    11.     }
    12.     catch(Exception $e){
    13.         //простор то какой!!!
    14.     }

    обрати внимание, что ты не только обрабатываешь ошибку "не ввел е-мэйл", а еще и все остальные ошибки о которых и подумать не мог.

    - сервер отключили
    - пропал интернет
    - удаленный комп не доступен
    - третяя мировая началась

    все при помощи одного механизма. и при всем при этом. как не странно, затрачиваешь меньше усилий, потому что не делаешь рекваред полей и валидат формы. странно да?

    я бы сформулировал правило: "если данные формы принимает класс, который так и так их проверит, то надо просто передать их ему. если форма накладывает спецефические ограничения на
    поля класса, например адреса могут быть только из домена mail.ru, проверять только на это специфическое ограничение, а в остальном по- прежнему в неотфильтрованном виде переправить классу".
     
  3. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    почему альтернативные? у меня методы правильные. альтернативные это у тех, кто как-то по-другому делает
     
  4. akrinel

    akrinel Активный пользователь

    С нами с:
    26 янв 2009
    Сообщения:
    955
    Симпатии:
    1
    Адрес:
    Spb
    ИМХО в той же JAVA исключения повсеместно юзаются и для тех ошибок которые в голову программисту обязательно придут. Но так удобнее, а в большинстве случаев человека время стоит дороже машинного времени.
     
  5. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Исключение это ситуация при которой программа в принципе не может продолжать корректную работу. Пользователь не совершенен и может допустить ошибку при заполнении формы и система должна предотвратить появление исключительной ситуации. Сделать она это может заранее проверив пользовательский ввод. Вот такая у меня позиция.

    Покажи мне код обработки 10 полей формы? Причём нужно вывести ошибки для каждого из 10 полей. Ещё я хотел бы узнать какая именно ошибка произошла и хотел бы установить своё собственно сообщение.
     
  6. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    [deleted]
     
  7. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    раз уж заговорили об исключениях, хочу прояснить картину. как известно, сначало то были только одни ифы. а ислючения появились уже намного позже. Никто не спорит что можно обрабатывать ошибки при помощи ифов. В четвертом ПХП только так и делали. И ничего все работало. Но вот наконец появились исключения. Они как бы отобрали часть работы у ифов. Совершенно определенный кусок. то что раньше писали
    PHP:
    1. <?php
    2. if ($mailer->send()) then{
    3. }
    4. else{
    5.     //обработка ошибок
    6. }
    теперь пишут
    PHP:
    1. <?php
    2. try{
    3.     $mailer->send();
    4. }
    5. catch(Exception $e){
    6.     //обработка ошибок
    7. }
    Вот из- за того, что одну и ту же вещь можно написать двумя разными способами и пошли эти споры, в головах какая-то путаница, где использовать if then, а где try throw catch. еще эти страшные тормоза, о которых говорил kostyl, вообще все усложняют. При всем при этом место, где должно стоять исключение видно в темноте и за километр. Никакой путаницы в этом нет.

    вот есть. к примеру, функция send(). надо просто задать себе один вопрос "что является результатом нормального завершения этой функции?" можно сказать, что результатом нормального завершения этой функции является отсылка указанного письма на указанные адреса со всеми аттачами и копиями. А все остальные завершения- это уже не нормальные и они должны выбрасывать эксепшен. неслучайно, что в ПХПДок исключения стоят сразу за описанием функции, потому что одно вырастает из другого. Согласен тут с akrinel, что это надуманное деление на какие-то обычные ошибки, которые можно было предусмотреть, и совсем уж исключительные ошибки, которые должны выбрасывать исключение. Все ошибки равны. Она помешала нормально завершиться функции? помешала. этого достаточно. значит это уже исключение.
     
  8. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    и нельзя кстати сказать, что исключения- это дебуг онли, как кос. Исключения всегда и во всех языках работают в релизах программ, точно как и ифы и все остальное. И в ПХП тоже, потому что пхп- это такой же язык.

    когда kostyl писал про то, что не надо ими заменять ифы, он наверное имел в виду, что не надо их использовать в совсем тривиальых случаях, например с единственной целью, чтобы убедиться, присвоена ли переменной значение или еще что-то такое. такое тоже встречал, пару раз сам грешил. это как из пушки по воробьям.
     
  9. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Ты так говоришь, как будто тут все противники исключений :) Я сам постоянно использую исключения и не думаю о том, что они могут какие-то тормоза добавить. Но сама идея отправки пользовательских данных без предварительной проверки мне чужда.

    Странно, но я чётко понимаю где надо выбрасывать исключение, а где возвращать результат работы.
     
  10. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Поделись, пожалуйста, с общественностью, не все понимают. Я, например, нифига не понимаю.

    Чем это:
    PHP:
    1. <?php
    2. $mail = new Mail;
    3. $mail->to([email='user@example.com]'user@example.com[/email]');
    4. $mail->body('Кучеряшки.');
    5.  
    6. if (!mail->send())
    7.    echo 'Мыло не послано:'.$mail->error;
    Хуже этого:
    PHP:
    1. <?php
    2. try {
    3.     $mail = new Mail;
    4.     $mail->to([email='user@example.com]'user@example.com[/email]');
    5.    $mail->body('Кучеряшки.');
    6.    $mail->send();
    7. catch(Exception $e){
    8.    echo 'Мыло не послано:'.$e;
    9. }
    И нафига оно ваще.

    Мыслями если поделишься буду рад. Можно полезными, на твой взгляд, ссылками.
     
  11. kostyl

    kostyl Guest

    страшные, имел я в виду, когда у тебя огромная иерархия классов исключений когда они именно были использованы нормально, и
    ...
     
  12. kostyl

    kostyl Guest

    lexaпопробуй, если не сложно, в обоих примерах померить память.... мне просто интересно
     
  13. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    lexa
    Тем, что пример слишком тривиален и как правило в реальной жизни не так всё просто. Вот чуть более сложный вариант к примеру (к сожалению к действительно сложному я не добрался, а искать щас уже не буду)

    PHP:
    1. <?php
    2. private function createNew()
    3. {
    4.     $is_preview = false;
    5.     if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    6.         try {
    7.             if (empty($_POST['tpl_name'])) {
    8.                 throw new Exception("Тема шаблона обязательна!");
    9.             }
    10.             if (empty($_POST['tpl_text'])) {
    11.                 throw new Exception("Текст шаблона обязателен!");
    12.             }
    13.             if (isset($_POST['preview'])) {
    14.                 throw new Exception('');
    15.             }
    16.             $sql = 'INSERT INTO templates
    17.                     VALUES(0, "'.$this->db->escape($_POST['tpl_name']).'", "'.$this->db->escape($_POST['tpl_text']).'", NOW())';
    18.  
    19.             $this->db->query($sql);
    20.             $id = $this->db->insertID();
    21.             $this->utils->forward('/templates/show/'.$id.'.html');
    22.         } catch (Exception $e) {
    23.             $message = $e->getMessage();
    24.             if ($message == '') {
    25.                 $is_preview = true;
    26.             } else {
    27.                 $this->parser->set('error', $message);
    28.             }
    29.             foreach ($_POST as $key => $val) {
    30.                 $this->parser->set($key, $val, true);
    31.             }
    32.         }
    33.     }
    34.     if ($is_preview) {
    35.         $this->parser->set('preview', true);
    36.         $this->parser->set('preview', $this->template('preview.htm'));
    37.     }
    38.     $this->parser->append('header_js', $this->template('fckeditor.htm'));
    39.     $this->parser->append('content_center', $this->template('new.htm'));
    40. }
     
  14. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    2Sergey89
    ни разу пока не откозывался от удобного инструмента только потому, что он медленно работает. мне по барабану. пусть компьютеры работают. я и так много работаю.
    на своем горьком опыте я пришел к заключению, что бизнеслогика должна отделяться от интерфейса. и пришел я к этому не от мвц а наоборот от этого к мвц, а от того, что меня стали закалебывать консольными приложениями. это меня выдресировало. поэтому я и советую другим представлять как себя будет вести класс в консольном приложении, даже если это никогде не будет консольным приложением. если у тебя прикладной класс не умеет работать кроме как в форме или умеет, но приучен получать данные в двойных слешах или что еще хуже работает и при этом что- то ищет в $_REQUEST (реально такое было :) ), то консольного приложения к сожалению не получится. Обработка ошибок внутри моделей- это лишь одно из звеньев такого отделения. форму убрал- ничего не должно сломаться.

    ты прав в том, что форма тоже должна сделать свои проверки. если к примеру у меня в движке какая-то функция определена

    PHP:
    1. <?php
    2. /**
    3. * @param int $x
    4. * @parem string $y
    5. **/
    6. function move(x, y=''){
    7. }
    то я по-любому ожидаю от пользователя как минимум один парам и причем именно инт, а не стринг или еще что по-хуже. то есть на форму возлагается проверка количества и типа данных. после этого она передает их внутрь движка и движок уже оценивает их прикладную пригодность. То есть например x должен быть больше 100 по-любому. Вот тут и возникает соблазн проверить x на это условие еще в форме. Потому что кроме как из формы эти данные как будто поступать все равно не будут. Это и есть смешение интерфейса с бизнеслогикой! прикладная корректность должна провериться внутри модели и если что сообщить об ошибке, естественно, в виде исключения. А о том как можно легко передать исключение из движка пользователю, я и написал в первом посте.

    Резюмируя все это, можно сказать, что лично я пришел к неутешительному для нас всех правилу: корректность данных должна проверяться в двух местах. И в форме и в модели. Причем в форме тип и количество, а в модели на прикладную пригодность. Правда опыт подсказывает, что проверку в форме чаще всего можно опустить, потому что без правильного количества модель все равно ругнется.
     
  15. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    2Psih
    вот как раз то, о чем я говорил. хороший пример того, как бывает, когда бизнеслогика смешана с интерфейсом.
     
  16. kostyl

    kostyl Guest

    alexey_baranov
    лично я не пишу консольных приложений, и поэтому проверяю не в модели ввод пользователя... Думаю в безвыходных ситуациях можно использовать исключения для передачи управления в другую точку программы, но явно не так как пример у Psih...
    Я обычно ставлю исключения для отлавливания своих ошибок и пишу их в лог или куда то там... Например, нет соединения с бд..., а проверять empty($_POST['tpl_name'] с помощью исключений, я считаю излишеством...
    Очень интересно услышать мнения 440Hz и флоппик.... Жду с нетерпением... ;)
     
  17. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    alexey_baranov
    Хайлоад есть хайлоад, внедрять туда 100% MVC слишком накладно, да и порой ограничивает в оптимизации. У меня максимально свободная свободная система и в приделах модуля я могу делать что хочу, не затрагивая остальные компоненты. Система доказала свою полную состоятельность и гибкость далеко не в одном проекте. Но это так, чисто для информации.
    К тому же, модуль это самостоятельная единица. Метод в данном случае выводит форму, он же её и проверяет. Шаблон в HTML. Если появляется необходимость повторять такое же действие где-то ещё - выносится в хелпер м глобальные шаблоны. Так что судить о системе по одному методу глупо.

    kostyl
    А чем плохо? Это у меня простая форма просто. А когда нужно проверить порядка 5-7 полей, да ещё и проверить при этом какие-то данные на существование в базе, а есть ли такой юзер, а есть ли у него вообще право сюда писать и.т.д? В этом случае проверка самих полей остаётся малой частью проверок. И городить в этом случае кучу ифов и держать и проверять флаг ошибки на каждом ифе это издевательство, а так же трата ресурсов. вот скажите, зачем мне делать 5-6 запросов в базу на проверку каких-то данных (договоримся что это необходимое условие для постинга формы, к тому же такие формы у меня бывали), если я знаю что в первом же поле уже ошибка? Правильно, я не буду делать ети запросы - я выкину исключение и перенесусть на 100-150 строк в низ сразу в обработку ошибок и отображу всю форму с уже заполненными пользователем данными и укажу ему на его ошибку.

    Никогда не думайте простейшим вариантом. Подумайте о том, когда ваша форма превратится в большого трансформера и условностями и динамически генерируемыми полями, когда от выбора юзера зависит какая опция появится. Поверте, на ифах замучаетесть, когда у вас будет очень сложное ветвистое условие обработки формы, когда у вас будет 3-4 условия, а в них куча подусловий - в каких-то случаях это ошибка, а в каких-то необязательное поле. Мараться с флагом ошибки просто заколебётесь. А если вдруг предусмотренная системой ошибка, как у меня preview, когда форму нужно отвалидировать, но сгенерировать типа ошибку, что бы в базу записи небыло и при этом отобразить как саму форму со всеми данными и в добавок preview?

    Любой инструмент хорош к своему месту. © Коллега
     
  18. kostyl

    kostyl Guest

    согласен, но я же оговаривал тот, что попроще...
     
  19. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    2Psih
    а фотки где? фотку тоже давай. покажи как пользователь узнает об ошибке. такие же две фотки как у меня. сначала перед отправкой, потом как получил ошибку.
     
  20. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    alexey_baranov, а как в твоём случае вывести ошибку напротив каждого поля?
     
  21. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    2Psih
    А ты не думал о том, чтобы делать мвц, но только как бы в одном классе? То есть если в мвц

    PHP:
    1.  
    2. <?php
    3. class Template extends Model{
    4.     public $name;
    5.     public $master;
    6.     public $born;
    7.  
    8.     public create(){}
    9.     public delete(){}
    10.     public rename(){}
    11. }
    12.  
    13. class TemplateView extends View{
    14.     function show(){}
    15. }
    16.  
    17. class TemplateCont extends Cont{
    18.     function init(){}
    19.     function action{}
    20. }
    сделать вот такой гибрид

    PHP:
    1. <?php
    2. class Template extends Component{
    3.     public $name;
    4.     public $master;
    5.     public $born;
    6.  
    7. //model
    8.     public create(){}
    9.     public delete(){}
    10.     public rename(){}
    11.  
    12. //view
    13.     function show(){}
    14.  
    15. //action
    16.     function init(){}
    17.     function action{}
    18. }
     
  22. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    alexey_baranov
    Посмотрел сообщения бегло - про фотки не нашел (а перечитывать всю ветку не буду, т.к. времени не много).

    Кратко - фотки проверяются на стороне сервера. Если с ними что-то не так - кидаем исключение с сообщением о проблеме с фоткой. Для обработки фоток у меня есть специальный хелпер, который этим занимается.
    З.Ы. Сохранить пусть к фоткам в type="file" полях вы не можете по причинам безопастности, так что юзеру придётся их заного выбирать в любом случае.
    З.Ы.Ы. И вообще - с исключениями можно выкинуть на обработку ошибок даже если у вас chained вызовы объектов и их разименовывание. С ифами так не сделать, т.е. вам придётся ошибку подымать как пузерёк пока он не дойдёт до последнего вызова, который и вернёт эту ошибку, т.е. в каждом методе по цепочке нужно проверить, а была ли ошибка. С исключенимями вас это нафиг не волнует - вы его кидаете и ловите в конце, обрабатываете и дальше делайте что вам надо - редирект, проставление данных и вывод формы с сообщением обшибке (мой вариант), завершаете работу приложения и.т.д.
     
  23. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    Вообще- то Сергей, я такого не делаю, но если бы стал, то сделал бы проверку внутри прикладного класса. я бы сложил все ошибки вместе и передал их наверх в исключении. А вьюшку страницы заставил бы это отобразить.

    PHP:
    1. <?php
    2. class Request extends Object{
    3.     function validate(){
    4.         $details= array();
    5.  
    6.         if (!$this->property['text'])
    7.             $details['text']='Заполните поле "Причина обращения"';
    8.         if (!$this->property['workobject'])
    9.             $details['workobject']= 'Выбирете объект обслуживания';
    10.         if (!$this->propertyByType(19978))
    11.             $details['i1']= 'Поручите заявку хотя бы одной функциональной группе';
    12.  
    13.         //вот тут немножечко похимичить. всесто обычного throw new Exception сделать вот так          
    14.         if ($details){
    15.             $error= new ValidateException("Неправильно заполнены поля заявки");
    16.             $error->details= $details;
    17.             throw $error;
    18.         }
    19.     }
    20. }
    При этом соблюдено главное правило мвц бизнеслогика никак не зависит от интерфейса. Это дает колоссальное преимущество при наследованиях. К примеру я могу пронаследовать от этого класса регламентную заявку, у которой обязательно к заполнению поле "скан". А валидэйт написать так parent::validate() и плюс проверить скан. если поменяется валидэйт обычной заявки, поменяется и валидэйт регламентной. если проверять все в формах, такого не добиться и плюс конечно прикладные классы получаются немного зависимы от интерфейса.
     
  24. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    ты меня не правильно понял. фотки- это скринсэйвы, на которых показано, как на твоем сайте пользователю сообщается об ошибке. я такие фотки выложил на первой странице этой темы.
     
  25. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    alexey_baranov
    Издеваетесь, да? Обычное отображение ошибок - строка в форме красным текстом. http://www.file.lu/signup.html если уж так интересно.