За последние 24 часа нас посетили 22828 программистов и 1250 роботов. Сейчас ищут 754 программиста ...

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

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

  1. Koc

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

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    Прочитал http://habrahabr.ru/blogs/php/30829/ , решил ее у себя использовать. Сделал set_error_handler('_aero_custom_error_handler', E_ALL & ~ E_NOTICE); // Это мой стандартный вариант показа ошибок пока что - все, кроме нотайсов.
    Но получается так, что она не обрабатывает не пойманные исключения. Какие еще есть варианты для оформления ошибок да исключений?
     
  2. kostyl

    kostyl Guest

    PHP:
    1.  
    2. <?
    3. function redirect_on_except($e)
    4. {
    5.   header('Location: ' . ERROR_PAGE);
    6.   $error_log_file = LOG_PATH . 'phpexp.log';
    7.   $error_string = "{$e->getCode()}:
    8.  Except text:
    9.  {$e->getMessage()}
    10.  in  file: {$e->getFile()}
    11.      line: {$e->getLine()}
    12.      trace: {$e->getTraceAsString()}
    13.  ";
    14.   if(file_exists($error_log_file)) {
    15.     $errors = file_get_contents($error_log_file);
    16.     if (!preg_match($error_string , $errors)) {
    17.       error_log($error_string, 3, $error_log_file);
    18.     }
    19.   }
    20.   else {
    21.     error_log($error_string, 3, $error_log_file);
    22.   }
    23.   exit;
    24. }
    25.  
    26. set_exception_handler("redirect_on_except");
    27.  
     
  3. Koc

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

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    ок, спасибо, будем ковырять в этом направлении
     
  4. kostyl

    kostyl Guest

    еще можешь в set_error_handler генерировать исключение, и оно будет отлавливаться в set_exception_handler.
    Но учти вообще, что исключения тормозная штука... Например, некотрые личности оперируют ими для реализации определенной логики работы - я противник этого, лучше реализовать чтото попроще, например, возвращать FALSE, а не генерировать исключение, чтобы потом перехватить его, узнать тип или сразу "определенно" перехватить и выполнить какойто код...
     
  5. Koc

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

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    да я в курсе, что они медленные. Это ж дебаг-онли, ессно форму контактную я не проверяю исключениями.
     
  6. alexey_baranov

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

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

    PHP:
    1. <?php
    2. function OnStore(){
    3.     $page= $this->m;
    4.  
    5.     $page->obj()->store();
    6.     TOR::db()->commit();
    7.     header на просмотр;
    8. }
    9.  
    И тут проблема, как всегда, а что же произойдет если внутри сторе() выплывет исключение? как его показать пользователю? редиректить куда- то не катит, потому что все что пользователь ввел на форме, пропадет, если даже он нажмет на кнопку "назад", все равно пропадет. А он может быть десять минут эту форму заполнял. Это приводит всех в ярость. Красивый вывод ошибки это не сгладит.
    Теперь я делаю так. ничего не меняю, что не может не радовать, только небольшая доделочка:

    PHP:
    1. <?php
    2. function OnStore(){
    3.     $page= $this->m;
    4.  
    5.     try{
    6.         $page->obj()->store();
    7.         TOR::db()->commit();
    8.         header на просмотр;
    9.     }
    10.     catch(Exception $e){
    11.         $page->error= $e;
    12.         $view= new PageView($page);
    13.         $view->show();
    14.         die;
    15.     }
    16. }
    17.  
    Это очень универсальный способ, чтобы обработать любую мыслимую и немыслимую ошибку пользователя. Особенно радует, что ничего не надо переделывать. Только добавил в модель Page поле $error и во вьюшке PageView в том месте, где начинается вывод содержания страницы, проверку, если $model->error, выводи вьюшку Exceptiona. Это все доделки. Тексты сообщений тоже уже есть в $message эксепшина. После этого все страницы заработали по новому, потому что они все пронаследованы от Page, а их вьюшки от PageView.

    Выглядит это вот так. сначала страница без ошибки, потом с ошибкой. как видно весь пользовательский ввод не потерялся. Для пользака очень удобно. почитал где ошибся, поправил и повторил. это им понравится.
    [​IMG]
    [​IMG]
    не очень красиво, потому что в дебуге, но смысл я думаю хорошо понятен.
     
  7. alexey_baranov

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

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    если есть у кого, выложите вьюшку нормальную для эксепшена.
     
  8. kostyl

    kostyl Guest

    alexey_baranov
    а что нельзя сделать, чтобы $page->obj()->store(); возвращал массив ошибок? намного все быстрее будет работать и проще как по мне...
     
  9. Koc

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

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    а как ты сохраняешь значение поле с input-file после перезагрузки страницы?

    х3, у меня пока все ошибки внутри одного класса обрабатываются. То есть есть класс ManagerManufacturers - управление производителями. Если пользователь ввел что-то неверное, то внутри этого класса я и показываю ошишки простой проверкой if($this->errors) {показать ошибки} else {залить значения в БД}.
     
  10. alexey_baranov

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

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

    kostyl Guest

    да как раз и нет, их придумали для того, чтобы чтото делать, когда не знаешь где ифы городить...
     
  12. alexey_baranov

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

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

    [​IMG]

    то есть если пользак долго заполнял форму и к своему неудовольствию обнаружил, что все равно заполнил ее неправильно, то при моем методе на форме сохраняются и все тексты, и все файлы.
     
  13. alexey_baranov

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

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

    kostyl Guest

    alexey_baranov
    я имею в виду что исключения придумали для того, чтобы отлавливать ошибки которые программисту в голову прийти не могут - исключительные ошибки... Если бы мы знали все ошибки которые могли произойти в приложении, то все программы бы были без ошибок. Вот для этого и придуманы исключения, чтобы отлавливать эти как бы скрытые от программиста ошибки - исключительные ситуации, которых теоретически возникнуть как бы не должно...
    В твоем примере ты передаешь ошибку чере message объекта исключения, вызывая исключение, которое и так можно предвидеть - неправильный ввод пользователя. Я же предлагаю делать тоже самое только с помощью массива. Если его размер ноль - то ошибок нету. Иначе циклом все вывел,
    и прекрасно при этом остаются на форме уже заполненные поля - это совсем другое...
    Я тоже раньше делал целую структуру классов исключений, продумывал ее, но когда посмотрел как всё тупит, то выкинул это из головы...
     
  15. alexey_baranov

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

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

    PHP:
    1. <?php
    2. if (!$this->to)
    3.     throw new MailException(бла бла бла укажите адрес)
    4. отправляю почту
    5.  
    а ты как в этой ситуации поступаешь?
     
  16. Sergey89

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

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Тут исключительная ситуация, потому что в класс не передали адрес отправки. А вот если бы юзер не указал адрес в форме, то это была бы контролируемая ошибка, которую можно отследить на этапе валидации формы.
     
  17. kostyl

    kostyl Guest

    в таком случае именно так :) но не как в другом твоем примере, потому что
     
  18. alexey_baranov

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

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

    И второй вопрос что делать, если логика работы класса изменится. к примеру, адрес не задали- значит отправляй на адрес по умолчинию. Я конечно поменяю реализацию класса, и потом еще должен буду поменять и форму тоже?
     
  19. kostyl

    kostyl Guest

    alexey_baranov
    я считаю, надо проверят данные обычными способами, до того как они попадут в класс, а в классе делать проверку с вызовом исключения только из-за того, что разработчик кода забыл вставить обычную проверку...
     
  20. Sergey89

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

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Ну да. Форма ведь не знает про устройство сервисного класса Mail. Она знает только, что сейчас от юзера требуется обязательный ввод e-mail адреса. А если меняются требования, то и форма изменяется под эти требования.
     
  21. alexey_baranov

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

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

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

    - все проверки в одном месте, то есть в сто раза меньше писанины

    - если надо изменить логику работы почтового класса, придется менять проверку только в одном месте
     
  22. alexey_baranov

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

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    поэтому проверки класса должны осуществляться внутри класса, а снаружи его использовать в try-catch.
     
  23. kostyl

    kostyl Guest

    alexey_baranov
    Чувствую Леха тебе можно написать книгу "Альтернативное методы и модели программирования"
    ps: я не смеюсь...
     
  24. Sergey89

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

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

    PHP:
    1.  
    2. <?php
    3. // ...
    4. $form->addField(
    5.     FormField::email('email')
    6.         ->setRequired()
    7.         ->setMax(50)
    8.     );
    9.  
    10. if ($request->isPost()) {
    11.     $form->import($request->getPost());
    12.  
    13.     if ($form->validate()) {
    14.         MailService::create()
    15.             ->setTo($form->getValue('email'))
    16.             ->setSubject('Hello');
    17.             ->send();
    18.     }
    19. }
     
  25. kostyl

    kostyl Guest

    alexey_baranov
    а вот у Сережки книги не будет, потому что таких книг много....
    :)