pipe — コレクションをコールバックに「渡して」結果を受け取る

  • カテゴリ: collection
  • 掲載バージョン: Laravel 12・PHP 8.4
  • 名前空間 / FQCN / コマンド: Illuminate\Support\Collection::pipe
  • 関連: tap / when / unless / pipeInto / map
  • 変更履歴: 特記なし

要点(TL;DR)

  • コレクション自身をコールバックに渡し、その戻り値をそのまま返すためのメソッド
  • 例:$sum = collect([1,2,3])->pipe(fn ($c) => $c->sum());
  • 罠:
    • チェーンは続かないことがある(コールバックが配列や数値を返すと以後はコレクションではない)
    • tapと違い元のコレクションは返らない
    • 型を厳密にするとTypeErrorになりやすい(Collection型ヒントの不一致)

概要

pipeは、現在のコレクションをコールバックにそのまま渡し、コールバックの戻り値を返すユーティリティです。
「この時点のコレクションを一旦別関数・サービスに渡して、結果を受け取りたい」場面で有効です。結果はコレクションに限らず、数値・配列・DTO など任意です。

構文 / シグネチャ

public function pipe(callable $callback): mixed;

引数(表)

引数必須既定値説明
$callbackcallable(Collection $collection): mixed✔︎コレクションを受け取り、任意の値を返す関数/クロージャ
  • 戻り値mixed(コールバックの戻り値そのもの)
  • 例外/副作用:コールバック内で発生した例外がそのまま伝播。pipe自体は非破壊でコレクションを変更しない。

使用例

最小例

<?php

declare(strict_types=1);

use Illuminate\Support\Collection;

require __DIR__.'/vendor/autoload.php';

$sum = collect([1, 2, 3])->pipe(fn (Collection $c) => $c->sum());

echo $sum; // 6

実務例

サービスクラスに委譲して集計→配列で返す。

<?php

declare(strict_types=1);

use Illuminate\Support\Collection;

require __DIR__.'/vendor/autoload.php';

final class OrderStats
{
    public function __invoke(Collection $orders): array
    {
        return [
            'count'   => $orders->count(),
            'revenue' => $orders->sum('amount'),
            'byStatus'=> $orders->groupBy('status')->map->count()->all(),
        ];
    }
}

$orders = collect([
    ['id' => 1, 'amount' => 1200, 'status' => 'paid'],
    ['id' => 2, 'amount' => 800,  'status' => 'pending'],
    ['id' => 3, 'amount' => 500,  'status' => 'paid'],
]);

$stats = $orders->pipe(new OrderStats());

/*
$stats = [
  'count' => 3,
  'revenue' => 2500,
  'byStatus' => ['paid' => 2, 'pending' => 1],
];
*/

コールバックがコレクションを返せば、チェーン継続も可能:

$names = collect([['name' => 'ann'], ['name' => 'Bob']])
    ->pipe(fn (Collection $c) => $c->pluck('name'))   // Collection を返す
    ->map(fn ($n) => ucfirst($n))
    ->values(); // ['Ann', 'Bob']

よくある落とし穴・注意

  • チェーン断絶:コールバックが非コレクションを返すと、以降はコレクションメソッドを呼べません。続けたい場合はコールバックでCollectionを返すか、最後にcollect()で包み直します。
  • tapとの違いtapは副作用を与えて元のコレクションを返すpipeコールバックの戻り値を返す。
  • LazyCollectionpipeの引数としてLazyCollectionが渡る場合、評価はコールバック次第。集計等で反復するとその時点でイテレーションが走ります。
  • 型ヒントcallable(Collection $c)のように型指定するなら、渡るのがLazyCollectionCollectionかを意識する(両対応にするならIlluminate\Contracts\Support\Arrayable|iterableなど柔らかい受け方も検討)。

代替・関連APIとの比較

  • tap:副作用を書いても元のコレクションでチェーン継続したい → tap
  • when / unless:条件に応じて処理をチェーン内で分岐したい → when/unless
  • pipeInto:コレクションを特定クラスのコンストラクタへ入力したい → pipeInto(Foo::class)
  • map:要素ごとの変換をしたい → mappipeは全体を一括で扱う)
  • Pipeline(Illuminate\Pipeline):複数ステップを通過させる処理の構造化 → アプリ全体のパイプラインに

テスト例(Pest)

<?php

use Illuminate\Support\Collection;

it('pipes collection to callback and returns its result', function () {
    $result = collect([1, 2, 3])->pipe(fn (Collection $c) => $c->sum());
    expect($result)->toBe(6);
});

it('does not mutate the original collection', function () {
    $c = collect([1, 2, 3]);
    $c->pipe(fn (Collection $x) => $x->sum());
    expect($c->all())->toBe([1, 2, 3]);
});

トラブルシュート(エラー別)

症状/エラー原因対処
Call to a member function map() on arraypipe配列を返した後にコレクションメソッドを呼んだコールバックでCollectionを返す/collect($array)で包む
TypeError: Argument 1 must be of type Collectionコールバックの型ヒントと実際に渡るインスタンスが不一致(LazyCollection等)型ヒントを緩めるか、collect()Collectionへ変換してから渡す
想定外に重い/遅いLazyCollectionに対して集計等で全件評価している遅延評価の理解を前提に、必要範囲で評価/ストリーム処理へ分割

コレクション固有の付記

  • チェーン可否:コールバックがCollectionを返す場合のみ継続可
  • 破壊的/非破壊:非破壊
  • キー保持:コールバックに依存(戻り値がCollectionなら、そのロジックに従う)
  • LazyCollection 対応:可
  • 計算量の目安O(1)(コールバックの計算量に依存)

入出力対応の小サンプル

入力コールバック出力
Collection([1,2,3])sum() を返すint(6)
Collection([['n'=>'a'],['n'=>'b']])pluck('n') を返すCollection(['a','b'])
LazyCollection($gen)count() を返すint(評価が走る)

参考リンク

レン (Wren)

こんにちは。レンです。

Laravelのコードの森に住んでいる、小さな案内役です。
ルーティングの枝やクラスの影を歩きながら、コードの流れや仕組みを眺めています。

このサイトでは、Laravelの基本から実装のコツまで、開発で役立つポイントを静かに整理しています。
難しいことを増やすのではなく、コードの見通しが少し良くなるヒントを届けるのが役目です。

「この処理はどこに書くのがいいのか」
「Laravelではどう考えると整理できるのか」

そんな疑問に、小さなメモを残すような気持ちで記事を書いています。

コードを書いている途中で迷ったとき、
このサイトが少し立ち止まって整理できる場所になればうれしいです。

レン (Wren)をフォローする