Ответы пользователя по тегу Исключения
  • Бросать исключение или возвращать коды ошибок/успеха? Является ли исключением то, что метод не может выполнить свою задачу?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Бросать исключение или возвращать коды ошибок/успеха?

    Бросать исключение.

    Является ли исключением то, что метод не может выполнить свою задачу?

    Конечно же.

    Но узнать является ли сумма(amount) корректной по-хорошему можно только в браузере/GUI или в Domain слое в самом методе transferMoney().

    К фронту не должно быть доверия, данные обязательно нужно проверять.
    Аргументы метода лучше проверять И на тип И на граничные значения. Например ваш amount по идее должен быть float + больше, или равен 0. Если amount таковым не является - бросайте исключение. Логика выше должна была это отсечь, еще на этапе валидации данных запроса.

    В transferMoney() нужно извлечь данные пользователя(который пересылает деньги) из БД и проверить есть ли у него такая сумма.

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

    Получается в методе transferMoney() есть одна причина неудачи, а что если добавится ещё одна причина, например, пользователю запрещено временно пересылать деньги?

    Тот же комментарий, что и про баланс.

    Поскольку они ожидаемые, то бросать исключения не логично.

    Почему же? Логика выше сможет обработать ваши ожидаемые исключения и через множественный catch определить, что не так. Это вполне нормально, и даже удобно.

    В случае если бы была одна причина неудачи, то можно было бы просто вернуть false.

    Очень хреновая практика. Как вы определите в вызывающем коде, что пошло не так? Что "false"? Баланса не хватает, нельзя делать покупки, или Меркурий в ретрограде?

    возвращать что-то на подобии [false, $error] и [true, null]

    Для php - это очень кривой подход. По двум причинам:
    1. Вы расширяете интерфейс метода, просто так.
    2. Вы нагружаете вызывающий код дополнительными обвязками проверок, опять же просто так.
    В этом нет смысла так как есть механизм try-catch, который отлично решает это задачу.
    Вот пример, допустим ваш transferMoney($amount, User $recipient) должен возвращать объект транзакции, пусть его сигнатура будет:
    transferMoney(float $amount, User $recipient): Transaction
    Вызывающий код знает, что он обязан в конце получить транзакцию, а если что-то пойдет не так - будет исключение, нет смысла в дополнительных проверках, а что если первый элемент массива false, а что если он true, но второй элемент не null, а что если второй элемент не тот, что ожидалось, а что если первый элемент - строка, и т.д.

    transferMoney() не должен подстраиваться под слой повыше, в нём не должно быть никаких предположений, что пользователь введёт что-то правильно или неправильно, он просто должен ожидать только валидные данные, если они неправильные, то это исключительная ситуация.

    Верно

    То есть transferMoney() выбросит исключение, которое подымется до Controller'a, и на основе которого Controller отправит 400 Bad Request и причину неудачи.

    Угу

    Или всё таки первый подход к проблеме лучше(первый абзац)?

    Первый подход - это путь боли, ошибок и отчаянья.

    Вот вам еще чтива: https://github.com/index0h/php-conventions
    Ответ написан
    1 комментарий
  • Исключения или проверка?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Однако не совсем понятно, было бы верным делать исключения в контроллере или все же сначала спросить сервис о например существовании мыла?

    Вы и так обрабатываете этот момент в catch блоке. Ваша реализация - ок.

    switch ($e->getCode())

    Лучше заведите больше исключений и используйте несколько catch.

    придется создавать отдельный метод someAuth где например не нужны сессии и требуется отправить сообщение о входе.

    Когда понадобится - напилите под этот тип авторизации отдельный сервис.
    Ответ написан
    3 комментария
  • Надо ли бросать исключение при приеме ошибочных (невалидных) данных?

    index0h
    @index0h
    PHP, Golang. https://github.com/index0h
    Нужно ли бросать исключение, в случаях, когда данные не прошли валидацию?

    Если это валидатор - достаточно вернуть ErrorResponse объект с ошибкой.
    Если это вызов метода с не правильным данными - бросайте исключение.

    Или достаточно просто занести код и сообщение ошибки в массив errors и при выводе работать с ним?

    Не стоит, возвращайте сразу ErrorResponse.

    Полезна ли информация с Исключений при валидации во время дебагга?
    Да, так вы получаете stacktrace, помимо сообщения об ошибке.

    Работа с ошибочными данными может вызвать ошибку непосредственно при их обработке.

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

    Вот вам пример, Assert::assert - это штука из либы ko-ko-ko/assert
    public function loginAction(Request $request) : Response
    {
        try {
            $userName = $request->request->get('userName');
            $password = $request->request->get('password');
    
            Assert::assert($userName, 'userName')->match('/^[\a-z\d]{3,32}$/i');
            Assert::assert($password, 'password')->lengthBetween(6, 32);
        } catch (\Throwable $exception) {
            return new Response($exception->getMessage(), Response::HTTP_BAD_REQUEST);
        }
    
        try {
            // Your business logic here
            
            return Response();
        } catch (\Throwable $exception) {
            $this->get('logger')->error($exception->getMessage(), ['exception' => $exception]);
            return new Response('Could not login', Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }
    Ответ написан
    1 комментарий