
Laravel rescue(): контрольований результат при помилці без великого try/catch
Як використовувати rescue() для резервного значення, автоматичного звітування про виняток, умовного report callback і короткої обробки необов’язкових операцій без великого try/catch.
Іноді виняток не повинен зупиняти весь запит. Наприклад, додатковий сервіс може не відповісти, але сторінка все одно може показати основні дані.
Якщо try/catch існує лише для того, щоб повернути резервне значення і, за потреби, повідомити про помилку, Laravel має коротку допоміжну функцію rescue().
Замість великого try/catch для простого резервного результату
try { $data = $service->load();} catch (Throwable $exception) { report($exception); $data = null;}$data = rescue( fn () => $service->load(), rescue: null, report: true,);rescue() виконує callback. Якщо все успішно, повертається його результат. Якщо всередині виникає виняток, Laravel може передати його стандартному механізму звітування і повернути резервне значення.
Тобто основний сценарій читається прямо: спробуй завантажити дані, а при помилці поверни null.
Без другого аргументу резервним значенням уже є null
$profile = rescue( fn () => $profileService->load($userId),);Якщо callback завершується успішно, $profile містить його результат. Якщо виникає виняток, rescue() за замовчуванням повертає null.
При цьому звітування про виняток також увімкнене за замовчуванням.
Резервне значення може бути не тільки null
$settings = rescue( fn () => $settingsService->load($userId), rescue: [], report: true,);Резервний результат варто підбирати так, щоб код після rescue() міг працювати з ним без додаткової плутанини. Якщо нормальний результат є масивом, часто логічніше повернути [], а не значення іншого типу.
Резервний результат може обчислюватися callback
$rates = rescue( fn () => $ratesService->loadCurrent(), rescue: fn (Throwable $exception) => $cache->get('rates:last-known', []), report: true,);Другий параметр може бути callback. Laravel передає в нього спійманий Throwable, тому резервна логіка може залежати від помилки або просто повернути останнє відоме значення з кешу.
Це корисно, коли fallback не є однією константою, але все ще залишається короткою і зрозумілою операцією.
report: true залишає помилку видимою
$preview = rescue( fn () => $previewService->build($document), rescue: null, report: true,);Резервний результат не означає, що помилку потрібно приховати. З report: true виняток передається у стандартний обробник винятків Laravel, але виконання поточного запиту продовжується.
Це одна з найсильніших сторін rescue(): користувацький сценарій може продовжитися, а технічна проблема все одно залишається видимою в системі звітування.
report: false використовуйте тільки для справді очікуваних помилок
$value = rescue( fn () => $optionalService->load(), rescue: null, report: false,);Можна вирішувати, які винятки звітувати
$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.
Огорніть тільки операцію, для якої резервний результат справді допустимий
$result = rescue(function () use ($order) { $this->validateOrder($order); $this->chargeCustomer($order); $this->reserveStock($order); $this->sendAnalytics($order); return $order;}, rescue: null);$order = $checkoutService->complete($order); $analytics = rescue( fn () => $analyticsService->send($order), rescue: null, report: true,);Критичний бізнес-процес не повинен мовчки перетворюватися на резервний результат. Якщо оплата або резервування товару не виконалися, код зазвичай повинен явно обробити цю помилку або дозволити їй піднятися вище.
Натомість необов'язкова аналітика після успішної основної операції може бути хорошим кандидатом для rescue(), якщо її помилка не повинна зламати відповідь користувачеві.
rescue() не робить повторних спроб
$result = retry( 3, fn () => $remoteService->load(), 200,);rescue() і retry() вирішують різні задачі. rescue() один раз виконує callback і дає контрольований результат після помилки. retry() призначений для повторного виконання операції.
За потреби їх можна поєднати, але тільки якщо повторна спроба справді має сенс для конкретної операції.
Коли звичайний try/catch залишається кращим
- коли різні типи винятків потребують різних дій;
- коли після помилки треба виконати кілька кроків відновлення;
- коли потрібне очищення ресурсів або окрема логіка
finally; - коли помилка є важливою частиною бізнес-процесу, а не просто причиною повернути резервний результат;
- коли явний
try/catchкраще пояснює складну поведінку.
Хороший rescue() не приховує помилку. Він чітко фіксує межу: ця конкретна операція може не вдатися, ось безпечний резервний результат, а ось правило, чи потрібно повідомити про виняток.




