Ці функції закривають типові шаблони коду, які інакше пишуть вручну з try, if і тимчасовими змінними.
retry - повторити операцію, що може тимчасово впасти:
$rate = retry(3, fn () => $client->fetchRate('USD'), 200);
// своя затримка для кожної спроби
retry([100, 500, 2000], fn () => $client->fetchRate('USD'));
// повторювати лише для певних помилок
retry(3, $callback, 200, fn (Throwable $e) => $e instanceof ConnectionException);
Затримка - у мілісекундах, може бути замиканням від номера спроби. Після останньої невдачі виняток кидається далі. Повторювати варто лише ідемпотентні операції: повтор POST на оплату може списати гроші двічі.
rescue - виконати й повернути запасне значення замість винятку:
$weather = rescue(fn () => $api->current($city), null);
$weather = rescue(fn () => $api->current($city), fn () => Cache::get("weather:$city"), report: false);
За замовчуванням виняток звітується (потрапляє в лог і Sentry), але не перериває запит. report: false - для очікуваних збоїв.
optional - безпечний доступ до властивостей null:
optional($user->address)->city;
У PHP 8 зазвичай краще nullsafe-оператор $user->address?->city. optional лишається корисним із замиканням: optional($user, fn ($u) => $u->fullName()).
tap - виконати дію над значенням і повернути саме значення:
return tap($user)->update(['last_login_at' => now()]); // повертає $user, а не true
value - повертає значення, а якщо це замикання - результат його виклику. Зручно для параметрів «значення або callback».
once - мемоізація в межах одного об'єкта чи запиту:
public function stats(): array
{
return once(fn () => $this->calculateExpensiveStats());
}
Повторні виклики stats() на тому самому екземплярі повернуть збережений результат. Для статичного контексту - один раз на запит.
Також: blank() / filled() (порожній рядок, пробіли, null, порожня колекція), transform() (застосувати callback, якщо значення не порожнє), when().
Міра: хелпер має робити код зрозумілішим. Ланцюжок tap(optional(value(...))) гірший за три рядки звичайного коду.