Collection::pipe
Passes the whole collection to a closure and returns whatever that closure returns.
public function pipe(callable $callback): mixedParameters
| Parameter | Type | Description |
|---|---|---|
$$callback | callable | Receives the collection itself as its only argument; its return value becomes the result of the call. |
Return value
mixedWhatever the callback returns — a collection, a scalar, an object, anything.
Every other collection method works on items; pipe works on the collection. It hands the whole instance to a callback and returns the callback's result, which is what lets you drop custom logic into the middle of a chain instead of breaking the chain apart into temporary variables.
When to reach for it
Three cases. Calling your own helper mid-chain (->pipe($this->summarise(...))). Computing something that needs the collection as a whole — an average, a ratio of one subset to another, a comparison between the first and last items. And branching, where a closure inspects the collection and decides which of several transformations to apply.
What trips people up
The return value is not forced back into a collection. If your closure returns a sum, the chain now holds an integer and the next collection method on the line will fail with a call-to-a-member-function error. Put value-producing pipes at the end of a chain, and always return the collection from a pipe you intend to keep chaining.
The closure receives a live reference to the same collection, so a mutating call such as transform or pop inside it changes the outer collection too. Related helpers: pipeInto passes the collection to a class constructor, pipeThrough runs it through an array of callbacks in turn, and tap is the version that always gives the collection back.
Example
When to use it
- Call a project-specific helper in the middle of a collection chain without a temporary variable.
- Compute an aggregate that needs the whole set, such as an average or a pass rate.
- Branch mid-chain, choosing a different transformation based on the collection's size or contents.
Frequently asked questions
What does the closure receive?
The collection instance itself, not the individual items. Type-hint the parameter as Illuminate\Support\Collection to get editor completion inside the closure.
Why did my chain break after a pipe?
Because the method returns exactly what the closure returned, and a closure ending in sum() or count() hands back a number rather than a collection. Return the collection if the chain must continue.
When should I use tap instead?
Use tap when the closure is only doing something on the side, such as logging or dumping — tap discards the closure's return value and always gives the collection back.
More examples
Branching inside the chain
The closure sees the whole collection and so can decide whether truncation is needed at all. The short list passes through unchanged; the long one prints Ada, Linus, Grace, and 2 more.
<?php
use Illuminate\Support\Collection;
$summarise = fn (Collection $c) => $c->count() > 3
? $c->take(3)->push('and ' . ($c->count() - 3) . ' more')
: $c;
echo collect(['Ada', 'Linus', 'Grace'])->pipe($summarise)->implode(', ') . PHP_EOL;
echo collect(['Ada', 'Linus', 'Grace', 'Ken', 'Barbara'])->pipe($summarise)->implode(', ') . PHP_EOL;pipe, pipeThrough and pipeInto
pipeInto hands the collection to a constructor and returns the new object, printing 100. pipeThrough runs a list of callbacks in order, each receiving the previous result, printing 90.
<?php
use Illuminate\Support\Collection;
class Report
{
public function __construct(public Collection $rows) {}
public function total(): int
{
return $this->rows->sum();
}
}
$rows = collect([10, 20, 30, 40]);
echo $rows->pipeInto(Report::class)->total() . PHP_EOL;
echo $rows->pipeThrough([
fn (Collection $c) => $c->filter(fn (int $n) => $n >= 20),
fn (Collection $c) => $c->sum(),
]) . PHP_EOL;pipe versus tap
pipe returns what the closure produced, so the first dump is the sorted [1, 2, 3]. tap ignores the closure's return value and always gives the original collection back, so the second dump is still [3, 1, 2] — use tap for side effects such as logging.
<?php
use Illuminate\Support\Collection;
$piped = collect([3, 1, 2])->pipe(fn (Collection $c) => $c->sort()->values());
$tapped = collect([3, 1, 2])->tap(fn (Collection $c) => $c->sort()->values());
print_r($piped->all());
print_r($tapped->all());
Discussion