Specification - правила як об'єкти
Виносить бізнес-правило в окремий об'єкт із промовистою назвою. Як комбінувати умови через AND/OR/NOT і де це краще за scope Eloquent.
Почніть вводити, щоб шукати по статтях, вакансіях, компаніях, проєктах, ресурсах, пакетах, подіях і користувачах.
Статті, новини, туторіали та переклади від учасників спільноти
Виносить бізнес-правило в окремий об'єкт із промовистою назвою. Як комбінувати умови через AND/OR/NOT і де це краще за scope Eloquent.
Якщо обробляється 50 000 елементів і застосовується 10 методів, звичайна колекція створить 10 копій у пам'яті.
Lazy колекції обробляють один елемент за раз.
Як працює:
Елемент проходить через усі методи і лише потім переходить до наступного.
Коли варто використовувати:
Порада: перетворити назад у звичайну колекцію - all().
// Погано: багато копій у пам'яті
$result = collect($hugeArray)
->filter(...)
->map(...)
->sortBy(...)
->take(100);
// Добре: один елемент за раз
$result = collect($hugeArray)
->lazy()
->filter(...)
->map(...)
->sortBy(...)
->take(100)
->all();
// Великий CSV
$users = LazyCollection::make(function () {
$h = fopen('users.csv', 'r');
while ($line = fgets($h)) {
yield $line;
}
fclose($h);
})->map(fn($l) => str_getcsv($l));
// cursor() - вже lazy
User::cursor();
Групує кілька змін у єдину транзакцію - усе або нічого. У Laravel роль виконує DB::transaction() з автокомітом, ролбеком і повтором при deadlock.
Потрібно подивитися стан колекції в середині ланцюга?
tap() дозволяє "підглянути" в колекцію, не змінюючи її.
Як працює:
Callback отримує колекцію, але повернуте значення ігнорується.
Сценарії:
Різниця з pipe():
$result = $users
->where('active', true)
->tap(fn($c) => logger("Active: {$c->count()}"))
->where('role', 'admin')
->tap(fn($c) => logger("Admins: {$c->count()}"))
->get();
// Порівняння
$collection->pipe(fn($c) => $c->count()); // повертає число
$collection->tap(fn($c) => $c->count()); // повертає колекцію
Потрібно застосувати складну логіку до всієї колекції?
pipe() передає в callback усю колекцію і повертає те, що callback повернув.
Переваги:
Різниця з map():
Порада: використовувати іменовані функції для читабельності.
$result = $users
->where('active', true)
->pipe(fn($c) => $c->sortBy('last_login')->take(10))
->values();
// Умовне сортування
$posts = Post::all()->pipe(function ($posts) use ($request) {
return $request->sort === 'popular'
? $posts->sortByDesc('views')
: $posts->sortByDesc('created_at');
});
// Дебаг
$result = $users
->where('active', true)
->pipe(fn($c) => tap($c, fn($c) => logger($c->count())))
->where('role', 'admin');
Зберігає не поточний стан, а послідовність подій, що його змінювали. Повний аудит і відтворюваність - ціною складнішої інфраструктури.
Команда Swoole відкрила вихідний код TypePHP - AOT-компілятора, що перетворює PHP-код у нативний машинний код через C++. Проєкт випущено раніше запланованого терміну й повністю написаний на PHP, включаючи самокомпіляцію.
Потрібно поділити користувачів на активних і неактивних?
partition() повертає одразу дві групи.
Різниця з filter():
Сценарії:
Порада: зручно для різних обробок двох груп.
[$active, $inactive] = $users->partition(fn($u) => $u->active);
// Дві різні обробки
$active->each(fn($u) => ...);
$inactive->each(fn($u) => ...);
// Валідація
[$valid, $invalid] = $orders->partition(fn($o) =>
$o->total > 0 && $o->email !== null
);
// Студенти
[$passed, $failed] = $students->partition(
fn($s) => $s->score >= 60
);
Розділяє операції зміни стану (команди) та читання (запити) на окремі моделі. Коли це виправдано у великих доменах і чому надмірне для CRUD.
Матеріали за темою «PHP»: усе, що ми писали про це українською. Нижче - суміжні теми, якщо шукаєте ширше.
Зараз опубліковано 87 матеріалів від 3 авторів. Останній матеріал - 11 вересня 2026.