laravel-rescue-replace-try-catch-fallback-tip.png
Шаблон кодуLaravel

Laravel rescue(): контрольований результат при помилці без великого try/catch

Як використовувати rescue() для резервного значення, автоматичного звітування про виняток, умовного report callback і короткої обробки необов’язкових операцій без великого try/catch.

Іноді виняток не повинен зупиняти весь запит. Наприклад, додатковий сервіс може не відповісти, але сторінка все одно може показати основні дані.

Якщо try/catch існує лише для того, щоб повернути резервне значення і, за потреби, повідомити про помилку, Laravel має коротку допоміжну функцію rescue().

Замість великого try/catch для простого резервного результату

До
php
try {    $data = $service->load();} catch (Throwable $exception) {    report($exception);     $data = null;}
Після
php
$data = rescue(    fn () => $service->load(),    rescue: null,    report: true,);

rescue() виконує callback. Якщо все успішно, повертається його результат. Якщо всередині виникає виняток, Laravel може передати його стандартному механізму звітування і повернути резервне значення.

Тобто основний сценарій читається прямо: спробуй завантажити дані, а при помилці поверни null.

У named arguments другий параметр називається rescue, а не default. Тому коректна форма: rescue: null.

Без другого аргументу резервним значенням уже є null

PHP - За замовчуванням повертається null
$profile = rescue(    fn () => $profileService->load($userId),);

Якщо callback завершується успішно, $profile містить його результат. Якщо виникає виняток, rescue() за замовчуванням повертає null.

При цьому звітування про виняток також увімкнене за замовчуванням.

Резервне значення може бути не тільки null

PHP - Порожній масив як резервний результат
$settings = rescue(    fn () => $settingsService->load($userId),    rescue: [],    report: true,);

Резервний результат варто підбирати так, щоб код після rescue() міг працювати з ним без додаткової плутанини. Якщо нормальний результат є масивом, часто логічніше повернути [], а не значення іншого типу.

Резервний результат може обчислюватися callback

PHP - Fallback callback отримує виняток
$rates = rescue(    fn () => $ratesService->loadCurrent(),    rescue: fn (Throwable $exception) =>        $cache->get('rates:last-known', []),    report: true,);

Другий параметр може бути callback. Laravel передає в нього спійманий Throwable, тому резервна логіка може залежати від помилки або просто повернути останнє відоме значення з кешу.

Це корисно, коли fallback не є однією константою, але все ще залишається короткою і зрозумілою операцією.

report: true залишає помилку видимою

PHP - Повернути fallback і повідомити про помилку
$preview = rescue(    fn () => $previewService->build($document),    rescue: null,    report: true,);

Резервний результат не означає, що помилку потрібно приховати. З report: true виняток передається у стандартний обробник винятків Laravel, але виконання поточного запиту продовжується.

Це одна з найсильніших сторін rescue(): користувацький сценарій може продовжитися, а технічна проблема все одно залишається видимою в системі звітування.

report: false використовуйте тільки для справді очікуваних помилок

PHP - Свідомо не повідомляти про очікувану помилку
$value = rescue(    fn () => $optionalService->load(),    rescue: null,    report: false,);
Не ставте report: false просто для того, щоб у логах стало тихіше. Якщо помилка означає реальну несправність, резервний результат може продовжити роботу користувача, але виняток краще залишити видимим.

Можна вирішувати, які винятки звітувати

PHP - Умовне звітування через callback
$value = rescue(    fn () => $service->load(),    rescue: null,    report: fn (Throwable $exception): bool =>        $exception instanceof RuntimeException,);

Параметр report може бути не тільки true або false. Callback отримує виняток і повертає boolean, тому можна звітувати лише про певні типи помилок.

rescue() ловить Throwable, а не тільки Exception

Поточна реалізація Laravel перехоплює Throwable. Це ширше за звичайний Exception.

Саме тому область навколо rescue() повинна бути вузькою. Не варто загортати в нього великий фрагмент коду, де серйозна програмна помилка може випадково перетворитися на звичайний null.

Огорніть тільки операцію, для якої резервний результат справді допустимий

До
php
$result = rescue(function () use ($order) {    $this->validateOrder($order);    $this->chargeCustomer($order);    $this->reserveStock($order);    $this->sendAnalytics($order);     return $order;}, rescue: null);
Після
php
$order = $checkoutService->complete($order); $analytics = rescue(    fn () => $analyticsService->send($order),    rescue: null,    report: true,);

Критичний бізнес-процес не повинен мовчки перетворюватися на резервний результат. Якщо оплата або резервування товару не виконалися, код зазвичай повинен явно обробити цю помилку або дозволити їй піднятися вище.

Натомість необов'язкова аналітика після успішної основної операції може бути хорошим кандидатом для rescue(), якщо її помилка не повинна зламати відповідь користувачеві.

rescue() не робить повторних спроб

PHP - retry() для повторних спроб
$result = retry(    3,    fn () => $remoteService->load(),    200,);

rescue() і retry() вирішують різні задачі. rescue() один раз виконує callback і дає контрольований результат після помилки. retry() призначений для повторного виконання операції.

За потреби їх можна поєднати, але тільки якщо повторна спроба справді має сенс для конкретної операції.

Коли звичайний try/catch залишається кращим

  • коли різні типи винятків потребують різних дій;
  • коли після помилки треба виконати кілька кроків відновлення;
  • коли потрібне очищення ресурсів або окрема логіка finally;
  • коли помилка є важливою частиною бізнес-процесу, а не просто причиною повернути резервний результат;
  • коли явний try/catch краще пояснює складну поведінку.

Хороший rescue() не приховує помилку. Він чітко фіксує межу: ця конкретна операція може не вдатися, ось безпечний резервний результат, а ось правило, чи потрібно повідомити про виняток.

#laravel-12 #laravel-13 #php-8-4 #php-8-5 #rescue #fallback #error-handling #exception-reporting

Схожі поради

laravel-throw-if-throw-unless-guard-clauses-tip.pngПорада
Переглянути пораду
#laravel-12 #laravel-13 #php-8-4 #php-8-5 #error-handling #throw-if #throw-unless #guard-clauses
laravel-withwherehas-avoid-duplicate-conditions-tip.pngПорада
Переглянути пораду
#eloquent #laravel-12 #laravel-13 #php-8-4 #php-8-5 #where-has #with-where-has #eager-loading #relationships
laravel-tap-side-effects-keep-original-value-tip.pngПорада
Переглянути пораду
#eloquent #laravel-12 #laravel-13 #php-8-4 #php-8-5 #tap #helpers #tappable
laravel-firstorcreate-replace-first-create-tip.pngПорада
Переглянути пораду
#eloquent #laravel-12 #laravel-13 #php-8-4 #php-8-5 #model-persistence #first-or-create #first-or-new