Помогите разобраться с исключениями

Европа - быстрые серверы на дисках NVMe от $5 / Русский датацентр от 199руб

Тема в разделе "Yii Framework", создана пользователем Forever, 1 фев 2019.

  1. Forever

    Forever Новичок

    Сообщения:
    65
    Ваш город:
    Korolev, Russia
    Address:
    Korolev, Russia
    Country:
    Location on Map:
    Сейчас изучаю Yii2 Framework, и заодно исключения.

    Вторые в своем коде редко когда применял раньше, с непривычки не могу понять, как же лучше это , особенно в MVC. Подскажите , как правильно переписать вот этот код , чтобы ивлечь всю пользу и удобство из из исключений:

    Есть форма регистрации TestForm.php, и в ней функция добавления пользователя в БД:
    Код:
    public function addUser()
        {
            if ($this->validate()){ //если все данные прошли фильтрацию, то
                  
                $user = new User(); // приписываем их пользователю
                $user->setRegDate();
                $user->login = $this->login;
                $user->setPassword($this->password);
                $user->email = $this->email;
                $user->setAuthKey();
                if ($user->save()){ // и сохраняем
                    return true;
                }
                          
            }
          
            return false;
          
        }
    есть контроллер формы, controller.php и там такое действие:
    Код:
     public function actionIndex()
        {
            $model = new TestForm();
            if ($model->load(Yii::$app->request->post()) && $model->addUser()){
                $model->answer = 'Ok';
            }
            else{
                $model->answer = 'Not ok';
            }
            return $this->render('index', ['model' => $model]);
        }
    Хотелось бы посмотреть пример добавления сюда механизма исключений, при котором, если просто валиация не прошла, то answer = Not Ok, если прошла, то Ok, а если по какой то причине $user->save не произошел, то answer = Извините, возникли технические неполадки". Заранее спасибо.
     
  2. AnrDaemon

    AnrDaemon Продвинутый новичок

    Сообщения:
    4.708
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Для начала хорошо бы понять, что исключение - это фатальная для продолжения корректной работы кода ситуация.
    Отсюда уже проще понять, где их стоит применять.

    А дальше,
    1. подобный код удобнее писать в обратном порядке (if(failed) throw new Exception; дальше нормальная обработка) - уменьшается количество структурных блоков, легче читать код;
    2. удобнее, когда валидация формы возвращает список ошибок, которые потом можно скопом отдать обратно клиенту;
    3. исключения можно использовать на разных стадиях, зависит от фреймворка.

    Выбери что-то одно. Либо исключения, либо код возврата.
     
  3. Forever

    Forever Новичок

    Сообщения:
    65
    Ваш город:
    Korolev, Russia
    Address:
    Korolev, Russia
    Country:
    Location on Map:
    Спасибо, разобрался более менее.
    А как лучше всего контролировать вывод сообщений для пользователя?
    Например, взять опять таки обычную форму.

    Нужно выводить три варианта сообщений над ней:

    1 )пользовательский ввод прошел проверку
    2) не прошел
    3) возникли технические проблемы при обработке запроса

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

    Как ты бы написал такую логику?
     
  4. AnrDaemon

    AnrDaemon Продвинутый новичок

    Сообщения:
    4.708
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Ты задаёшь вопрос исходя из предположения, что существует какой-то универсально лучший способ… его нет.

    Если брать, скажем, условно-типичную форму регистрации, то даже тут в трёх полях масса вариантов и тонкостей.
    Какие-то проверки можно с уверенностью производить прямо на клиенте, что-то придётся обрабатывать на сервере, явно либо через XHR.

    И, да, форма должна быть готова отобразить дополнительную информацию. Это делается добавлением до времени невидимых блоков, которые заполняются и отображаются скриптом.
     
  5. grigori

    grigori ( ͡° ͜ʖ ͡°) Команда форума

    Сообщения:
    7.125
    Ваш город:
    Stormwind
    Address:
    Scottsdale, United States
    Country:
    Location on Map:
    К сожалению, несколько фреймворков, в их числе yii и slim, используют исключения не по назначению.
    Например, чтобы вернуть 404 или 301, надо бросить исключение определенного класса.
     
  6. grigori

    grigori ( ͡° ͜ʖ ͡°) Команда форума

    Сообщения:
    7.125
    Ваш город:
    Stormwind
    Address:
    Scottsdale, United States
    Country:
    Location on Map:
    Дело в том, что "как бы мы написали" и "yii-way" - это религиозно разные подходы. В Yii есть инструменты, которые помогают сделать это быстро. Мы бы делали это в разы дольше, потому что мы делаем сложные сайты, которые простыми инструментами не сделать.
     
  7. grigori

    grigori ( ͡° ͜ʖ ͡°) Команда форума

    Сообщения:
    7.125
    Ваш город:
    Stormwind
    Address:
    Scottsdale, United States
    Country:
    Location on Map:
    перенес, вопросов по теории тут нет
     
  8. AnrDaemon

    AnrDaemon Продвинутый новичок

    Сообщения:
    4.708
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Не надо путать код возврата из процедуры и код ответа сервера… В данном случае использование исключения в связке с глобальным обработчиком исключений вполне оправдано.
     
  9. grigori

    grigori ( ͡° ͜ʖ ͡°) Команда форума

    Сообщения:
    7.125
    Ваш город:
    Stormwind
    Address:
    Scottsdale, United States
    Country:
    Location on Map:
    @AnrDaemon, ты вопрос-то читал?
    какой еще код возврата из процедуры, это не С
     
  10. whirlwind

    whirlwind TDD infected, paranoid

    Сообщения:
    1.939
    Ваш город:
    Spb
    Address:
    Spartanburg, United States
    Country:
    Location on Map:
    Исключения для управления это плохо. Есть такая штука exception safety. Возможность форсировать стек легко приводит к side effects -> exception safety -> object/data inconsistency
    Это способ стрельнуть себе в ногу. Просто в силу специфики PHP lifetime ноги не критичная штука.

    ну он скорее всего имел в виду способ доставки
     
  11. AnrDaemon

    AnrDaemon Продвинутый новичок

    Сообщения:
    4.708
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Хорошо, из функции, педант Вы наш…
     
  12. grigori

    grigori ( ͡° ͜ʖ ͡°) Команда форума

    Сообщения:
    7.125
    Ваш город:
    Stormwind
    Address:
    Scottsdale, United States
    Country:
    Location on Map:
    в общем, я не согласен с алгоритмом возврата 404 через throw new HTTPException,
    потому что 404 и 301 - валидная и штатная ситуация для приложения, и проектировать эту страницу надо через штатный слой view,
    но индусам нравится, а их несколько миллионов
     
  13. WMix

    WMix герр M:)ller Партнер клуба

    Сообщения:
    6.367
    Ваш город:
    Berlin
    Address:
    Berlin, Germany
    Country:
    Location on Map:
    и как ты это делаешь?
    PHP:
    public function action(){
      if(!
    $found$view->render('404');
    }
     
  14. AnrDaemon

    AnrDaemon Продвинутый новичок

    Сообщения:
    4.708
    Ваш город:
    Moscow, Russia
    Address:
    Moscow, Russia
    Country:
    Location on Map:
    Для какого слоя приложения это штатная ситуация?
    Для HTTP? Да.
    Для бизнес-логики? Бизнес-логике до HTTP дела нет, она сказала "[бибип] отсюда, нет у меня такой [бибип]".
    HTTP слой отловил этот бип и конвертировал его в 404.
     
  15. whirlwind

    whirlwind TDD infected, paranoid

    Сообщения:
    1.939
    Ваш город:
    Spb
    Address:
    Spartanburg, United States
    Country:
    Location on Map:
    Ура, холивар! )

    Для 500 это норм ситуация.

    PS. Мне нравится Java-way. Там есть дефолтные хендлеры и при этом респонз - объект. Можно свой стайл выбрать. Но исключения никогда не дадут необработанный результат, что тоже верно.
     
  16. Adelf

    Adelf Laravel&PhpStorm Команда форума

    Сообщения:
    3.359
    Ваш город:
    Казань
    Address:
    Kazan, Russia
    Country:
    Location on Map:
    Причем тут ява? Во многих php фреймворках тоже есть и респонс обьект и дефолтные хендлеры. Но это холивар, да. уже долгий.
    Проблема пути без исключений - необходимость постоянно вручную пробрасывать ошибку наверх.
    Проблема пути с исключениями - необходимость контролировать как бы исключение не выскочило не в том контексте(какой-нибудь неудачный findOrFail приведет к 404 ошибке, хотя это не всегда должно происходить). да и множественные ошибки не всегда удобно обрабатывать.
     
  17. whirlwind

    whirlwind TDD infected, paranoid

    Сообщения:
    1.939
    Ваш город:
    Spb
    Address:
    Spartanburg, United States
    Country:
    Location on Map:
    Ну это как написать. Есть такая штука IoC. Представь другой кейс, например UI для standalone. Думаешь там декомпозиция и количество уровней иерархии классов поменьше чем в вебе? Нет. Но там ни у кого мозгов не хватает исключениями рисовать на экране. Просто люди делают как проще. И если это не вызывает особых проблем, то подход приживается.
     
  18. Adelf

    Adelf Laravel&PhpStorm Команда форума

    Сообщения:
    3.359
    Ваш город:
    Казань
    Address:
    Kazan, Russia
    Country:
    Location on Map:
    ты предлагаешь напрямую просить обьект веб-респонса? или что?

    Ну конкретно экрано-рисовательная часть довольно плоская. там нет проблем вроде. А именно application слой вполне может ловить исключения об ошибке(сервер не отвечает!!) и отдавать нормальный ошибочный объект(не исключение) рисовательному слою.
     
  19. whirlwind

    whirlwind TDD infected, paranoid

    Сообщения:
    1.939
    Ваш город:
    Spb
    Address:
    Spartanburg, United States
    Country:
    Location on Map:
    Ничего не надо просить. TDA

    Если речь про валидацию, то я предлагаю объект validation result, который отвязан от локали и оперирует например сетом кодов и ключевых параметров. Этот кусок логики относится к конкретному контроллеру и не нуждается в размазывании по иерархии, его не нужно никуда передавать. После обращения к валидаторам можно это объект-результат стандартным конвертером преобразовать в что то нужное на стороне браузера.

    А если речь про именно исключения, то здесь top-level exception хендлер вокруг точки входа во фронт контроллер/роутера что бы сделать правильный fail fast и это будет 500. Все эти 40X это кейсы строго в одном месте возникают около одной точки и хендлить их гдето внутри контроллеров это явно создавать проблему. Для всех остальных случаев для каких целей http response code устанавливать, для понтов? Если это какой то rest протокол поверх http, то тем более response объект и коды по своим правилам.

    И в итоге видим, что в обычных случаях для ответа исключения не нужны, потому что проблему ты обозначил правильно. А в исключительных просто обрабатываются каким то top-level хендлером. Исключения остаются исключениями. Способом защиты системы от непредвиденных (неучтенных/нежелаемых к обработке) кейсов.

    Вообще форсировать стек это всегда очень плохо. Это типа объектно-ориентированного goto. Ну представь, ты сделал рефакторинг и заюзал какой нибудь декоратор который стату считает после вызова декорируемого объекта, а потом в глубине иерархии вызовов кидаешь исключения. Исключение пролетает код декоратора мимо и какой нибудь счетчик в этом декораторе что нибудь не учитывает. Система сломалась.
     
  20. grigori

    grigori ( ͡° ͜ʖ ͡°) Команда форума

    Сообщения:
    7.125
    Ваш город:
    Stormwind
    Address:
    Scottsdale, United States
    Country:
    Location on Map:
    1. Давай определимся, HTTP слой - это View или контроллер?
    "конвертировал его в 404" - это view. У тебя View ловит исключения? Нелепость получается. Исключения должен ловить контроллер, и вызывать View - это его роль.

    2. В Yii бизнес-логика бросает исключение HttpException - это смешение View с моделью. Именно это мне не нравится. Не должна модель оперировать HttpException, она должна бросать свое исключение.