Где и как лучше прехватывать/обрабатывать исключения?

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

Есть код, он должен сохранить пользователя. В этом примере мы можем получить Exception в 3 разных местах.

Как я сейчас представляю, обернуть вызов метода сервиса в контроллере в try catch. Поскольку в обязанность контроллера входит генерирование ответа пользователю в зависимости от результата. Но, меня смущают некоторые нюансы:

  • В случаи большого количества возможных исключений методы контроллера превратятся в простыню из catch.
  • Еще и ошибку нужно записать в лог.

Если обрабатывать ошибку по месту, возникает проблема в возврате обратно данных по цепочке. Это наплодит кучу if-ов и усложнит разные методы разными типами возврата.

Если поместить try catch в сервис и возвращать контроллеру к примеру User|false, как тогда контроллер будет генерировать ответ, если он не будет знать в чем проблема, в базе или в том, что это дубликат.

Может лучшим способом будет обрабатывать все ошибки через set_exception_handler?

class UserController
{
    private UserSerivce $service;

    public function store(array $data)
    {
        $user = $this->service->new($data);

        return redirect()->to('/' . $user->id);
    }
}

class UserSerivce
{
    private UserRepository $repository;

    public function new(array $data): User
    {
        $user = new User($data['name']); //InvalidArgumentException

        $user = $this->repository->add($user);

        return $user;
    }
}

class UserRepository
{
    public function __construct()
    {
        $this->builder = new PDO(''); //PDOException
    }
    public function add(User $user): User
    {
        $saved = $this->builder->query('INSERT INTO users (name) VALUES ("user")'); //PDOException
    }
}

class User
{
    private string $name;

    public function __construct(string $name)
    {
        if (empty($name)) {
            throw new InvalidArgumentException('Name is empty');
        }
        $this->name = $name;
    }
}

Ответы (0 шт):