Пользовательские исключения в Laravel

Пользовательские исключения в Laravel

Довелось столкнуться с проектом на Laravel, напичканным конструкциями try catch, что, с моей точки зрения, в большинстве случаев является не совсем верным решением. Это и послужило триггером для этой небольшой статьи.

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

<?php

namespace App\Http\Controllers;

use App\Services\ProductService;

class ProductController extends Controller
{
    public function index()
    {
        try {
            (new ProductService)->doSomething();
        } catch (\Exception $e) {
            return response()->json([
                'message' => $e->getMessage()
            ]);
        }
    }
}

 

Для полноты картины класс ProductService:

<?php

namespace App\Services;

class ProductService
{
    public function doSomething()
    {
        // if something went wrong
        throw new \Exception('This is my custom exception');
    }
}

 

Суть в том, что в подобных случаях нет никакой надобности отлавливать исключение в контроллере. Просто дайте ему всплыть и обработайте его в методе render класса Handler (app/Exceptions/Handler.php). А ещё лучше - создайте свой класс и пропишите обработку в нём. Пройдёмся пошагово.

Создаём класс исключения:

php artisan make:exception MyCustomException --render

 

Открываем только что созданный класс и дополняем код:

<?php

namespace App\Exceptions;

use Exception;

class MyCustomException extends Exception
{
    public function render($request)
    {
        return response()->json([
            'error' => $this->getMessage()
        ]);
    }
}

 

Примечание: если используете sentry, можно добавить метод report.

Далее подправим ProductService:

<?php

namespace App\Services;

use App\Exceptions\MyCustomException;

class ProductService
{
    public function doSomething()
    {
        // if something went wrong
        throw new MyCustomException('This is my custom exception');
    }
}

 

И уберём всё лишнее из контроллера:

<?php

namespace App\Http\Controllers;

use App\Services\ProductService;

class ProductController extends Controller
{
    public function index()
    {
        (new ProductService)->doSomething();
    }
}

 

В конечном счёте результат будет точно таким же, но код намного чище.

Успехов!