Laravel Collections: Beyond the Basics
Laravel Collections: Tips & Tricks
Laravel Collections: Tips & Tricks
Tip: Use tap() for Debugging
$users->tap(fn($c) => dump($c->count()))
->filter(fn($u) => $u->active)
->map(fn($u) => $u->name);
Inspect the collection mid-chain without breaking the flow.
Gotcha: map() Preserves Keys
collect([1 => 'a', 2 => 'b'])->map(fn($v) => strtoupper($v));
// [1 => 'A', 2 => 'B'] — keys preserved
Use values() to reset keys: ->map(...)->values().
Tip: when() for Conditional Operations
$collection->when($condition, fn($c) => $c->filter(...));
Cleaner than if statements in chains.
Tip: pipe() for Custom Transformations
$result = $collection->pipe(function ($items) {
return $items->sum('price') / $items->count();
});
Gotcha: each() vs map()
each() is for side effects (returns original collection). map() transforms (returns new collection).
Tip: Lazy Collections for Large Datasets
User::cursor()->lazy()->filter(fn($u) => $u->active)->each(fn($u) => process($u));
Processes one record at a time, no memory issues.
Tip: groupBy() with Multiple Keys
$users->groupBy(['department', 'role']);
// Nested grouping: department -> role -> users
Gotcha: contains() Uses Loose Comparison
collect([1, 2, 3])->contains('1'); // true (loose)
collect([1, 2, 3])->containsStrict('1'); // false
Tip: reduce() for Accumulation
$total = $orders->reduce(fn($carry, $order) => $carry + $order->total, 0);
Tip: crossJoin() for Combinations
collect(['A', 'B'])->crossJoin(['1', '2']);
// [['A', '1'], ['A', '2'], ['B', '1'], ['B', '2']]
Tip: Use route:cache Carefully
php artisan route:cache is fast, but it doesn't work with closure-based routes. Every time you cache routes, Laravel serializes them. If you have Route::redirect() or closure callbacks, the cache breaks. Stick to controller-based routes in production.
Tip: Model APP_KEY Rotation
Rotating APP_KEY invalidates all encrypted data — cookies, encrypted DB columns, and password reset tokens. If you must rotate (e.g., after a leak), plan a migration that re-encrypts existing data with the new key.
Gotcha: Local Scope Leaks
Global scopes defined in booted() apply to ALL queries on that model — including relationships. An innocent User::all() in admin panel might exclude soft-deleted users if a global scope is active.
Senior Insight
Laravel collections are elegant, but they hide performance costs that can bite you at scale. I once profiled an API endpoint that used filter()->map()->values() on a 50K-element collection — it looked clean but took 2.3 seconds. The database query could have done the same work in 20ms. My rule: collections are for presentation logic (reformatting, sorting display data). For data filtering and aggregation, push the work to the database.
Source: Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/laravel), Spatie Blog (https://spatie.be/blog)