Замість реєструвати колбеки в bootstrap/app.php можна описати поведінку прямо в класі винятку - методами report() і render(). Обробник Laravel викличе їх сам.
namespace App\Exceptions;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
final class InsufficientBalanceException extends Exception
{
public function __construct(
public readonly int $required,
public readonly int $available,
) {
parent::__construct('Недостатньо коштів на балансі.');
}
public function report(): bool
{
// очікувана бізнес-ситуація, звітувати не потрібно
return true;
}
public function render(Request $request): Response|JsonResponse
{
if ($request->expectsJson()) {
return response()->json([
'message' => $this->getMessage(),
'required' => $this->required,
'available' => $this->available,
], 422);
}
return back()->withErrors(['balance' => $this->getMessage()]);
}
}
Як працюють значення, що повертаються:
| Метод | Повертає | Результат |
|---|---|---|
report() |
false |
стандартне логування виконується |
report() |
true чи нічого (void) |
виняток вважається обробленим, стандартного логування немає |
render() |
відповідь | її отримає користувач |
render() |
false |
стандартний рендеринг Laravel |
Навіщо власні винятки:
- доменна мова:
InsufficientBalanceExceptionу коді й логах зрозуміліше, ніжRuntimeException('balance'); - дані в полях: скільки потрібно, скільки є - а не розбір тексту повідомлення;
- точкові
catch: викликаючий код ловить саме цей випадок, а несподівані помилки летять далі; - одне місце для того, як ця ситуація виглядає для користувача.
Коли краще колбеки в bootstrap/app.php: для чужих винятків (з пакетів чи фреймворку), до класу яких немає доступу, і для спільної політики - наприклад, усі помилки API в одному форматі.
Порада щодо ієрархії: базовий виняток модуля (BillingException) і конкретні нащадки - тоді можна зловити все, що стосується модуля, одним catch, а звітування налаштувати для базового класу.
Докладніше в документації: Помилки: винятки з власним рендерингом