Laravel's collection fluent interface is powerful, but deeply nested closures quickly become unreadable. Here's when and how to refactor.
## The Problem: Triple-Nested Closures
“`php
return $dates->map(function($date) use ($variants, $allPricing, $defaults) {
return new DatePrice(
$variants->map(function($variant, $key) use ($date, $allPricing, $defaults) {
$match = $allPricing->filter(function($pricing) use ($date, $variant) {
return $pricing->date === $date && $pricing->variant === $variant;
})->first();
return $match?->price ?? $defaults[$key];
}),
$date
);
});
“`
This is doing too much in one statement:
1. Filtering pricing by date and variant
2. Falling back to default if not found
3. Mapping across all variants
4. Creating the final structure
## The Solution: Extract Inner Logic
Pull the innermost logic into a private method:
“`php
private function findPriceForVariantOnDate(
Collection $allPricing,
array $variant,
string $date,
?Price $defaultPrice
): ?Price {
return $allPricing
->filter(fn($p) => $p->date === $date && $p->matchesVariant($variant))
->first()?->price ?? $defaultPrice;
}
“`
Now the main logic becomes clear:
“`php
// Restructure: one DatePrice per date, containing prices for all variants
return $dates->map(function($date) use ($variants, $allPricing, $defaults) {
return new DatePrice(
$variants->mapWithKeys(function($variant, $key) use ($date, $allPricing, $defaults) {
$price = $this->findPriceForVariantOnDate(
$allPricing,
$variant,
$date,
$defaults[$key]
);
return [$key => $price];
}),
$date
);
});
“`
## When to Extract
**Extract when:**
– 3+ levels of nesting
– Inner logic is reused elsewhere
– The closure has complex conditionals
– You need to unit test the inner logic separately
**Keep inline when:**
– 1-2 levels of nesting with simple operations
– The closure is very short (1-2 lines)
– Extraction would require passing 5+ parameters
## Naming Matters
The extracted method name should read like documentation:
– `findPriceForVariantOnDate()` – immediately clear what it does
– `matchesVariant()` – better than `in_array($variant, $pricing->variants)`
– `getDefaultPrices()` – better than `$fallbacks`
Future developers (including you) will thank you.
Leave a Reply