- カテゴリ: collection
- 掲載バージョン: Laravel 12・PHP 8.4
- 名前空間 / FQCN / コマンド:
Illuminate\Support\Collection::tap - 関連: each / pipe / when / unless / tap(ヘルパ)
- 変更履歴: —
要点(TL;DR)
- チェーンの途中で「ログを書く」「計測する」など副作用を実行し、同じコレクションを返す。
- 最低限の使い方:
$c = collect([1,2,3])->tap(fn ($c) => Log::info('count', ['n' => $c->count()])); - 罠:コールバックの戻り値は捨てられる/変換したいなら
pipeやmap/内部で要素を直接変更すると破壊的。
概要
tap はコレクションを引数に受け取るコールバックを一度呼び出し、その後元のコレクション(同一参照)を返します。ログ記録・タイミング計測・デバッグ出力・メトリクス送信など、チェーンを途切れさせずに副作用を挟みたい場面で使います。
構文 / シグネチャ
public function tap(callable $callback): static
引数(表)
| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
$callback | callable(Collection $collection): void | はい | — | コレクションを受け取り、副作用を実行。戻り値は無視される |
- 戻り値:
static(同じインスタンスを返す) - 例外/副作用:コールバック内で投げられた例外がそのまま伝播。I/O(ログ/DB/外部API)等の副作用はコールバックに依存。
使用例
最小例
<?php
use Illuminate\Support\Collection;
// 標準出力に要素数を出すだけ(純PHPで依存少なめ)
$nums = collect([10, 20, 30])
->tap(fn (Collection $c) => file_put_contents('php://stdout', "count={$c->count()}\n"));
// $nums は [10, 20, 30] のまま(同一インスタンス)
実務例
<?php
use App\Models\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
// 非アクティブユーザーを取得して処理する前にメトリクスを記録
$users = User::query()
->where('active', false)
->get()
->tap(function (Collection $c) {
Log::info('deactivate_candidate_count', ['count' => $c->count()]);
});
// 以降のチェーンはそのまま継続可能
$users->each->update(['active' => true]);
よくある落とし穴・注意
- 戻り値は無視:
tap(fn () => 123)の123は使われません。形を変えたいならpipe(チェーンの値を差し替える)、要素変換はmap。 - 非破壊だが中で破壊し得る:
tap自体は非破壊。コールバックで要素を参照変更すれば結果は変わります。意図しない変更に注意。 - 例外はそのまま伝播:ログ送信やAPI呼び出しを入れる場合は失敗ハンドリングを。
- パフォーマンス:O(1)。反復処理は行いません。
- キー保持:影響なし(そのまま)。
代替・関連APIとの比較
each:各要素に対して副作用を実行。ループが必要なときはこちら。pipe:コレクションをコールバックへ渡し、コールバックの戻り値でチェーンの値を差し替える。when/unless:条件に応じてサブチェーンを実行。tap(グローバルヘルパ):任意の値に対して同様のパターンを適用。コレクション以外の変数にも使える。
選定基準:
- 「副作用だけして元のコレクションで続けたい」→
tap - 「変換結果で続けたい」→
pipe - 「各要素に対する副作用」→
each - 「条件付きでチェーンを分岐」→
when/unless
コレクション固有メモ
- チェーン可否:可
- 破壊的/非破壊:非破壊(ただしコールバック内で破壊可能)
- キー保持:保持
- LazyCollection 対応:可(同じく O(1)、コールバックは即時実行)
- 計算量の目安:O(1)
入出力対応(サンプル)
| 入力 | tap 内の副作用 | 出力 |
|---|---|---|
collect(['a' => 1, 'b' => 2]) | Log::info('count', ['n' => 2]) | 同じ Collection(['a' => 1, 'b' => 2]) |
テスト例(Pest)
<?php
use Illuminate\Support\Collection;
it('calls callback and returns same instance', function () {
$called = false;
$c = collect([1, 2, 3]);
$same = $c->tap(function (Collection $x) use (&$called, $c) {
expect($x)->toBe($c);
$called = true;
});
expect($called)->toBeTrue();
expect($same)->toBe($c); // 同一インスタンス
});
トラブルシュート(エラー別)
| 症状/エラー | 原因 | 対処 |
|---|---|---|
Call to undefined function collect() | フレームワーク外/オートロード未設定 | Laravel 環境で実行 or illuminate/support を読み込む |
Class "Log" not found | ファサード未インポート or 設定未了 | use Illuminate\Support\Facades\Log; を追加、ロギング設定を確認 |
| 副作用が実行されない | コールバック未実行箇所(早期 return 等) | tap の位置を見直し、実行経路を確認 |
| 期待した変換が反映されない | tap は戻り値を無視 | 変換は pipe / map を使用 |
参考リンク
- Laravel 12 ドキュメント「Collections」:https://laravel.com/docs/12.x/collections
- Laravel 12 ドキュメント「Helpers: tap」:https://laravel.com/docs/12.x/helpers#method-tap
- フレームワーク実装(Collection)ソース:https://github.com/laravel/framework/blob/12.x/src/Illuminate/Support/Collection.php
- フレームワーク実装(LazyCollection)ソース:https://github.com/laravel/framework/blob/12.x/src/Illuminate/Support/LazyCollection.php

