transform — コレクション要素を破壊的に置き換える

collection
  • カテゴリ: collection
  • 掲載バージョン: Laravel 12・PHP 8.4
  • 名前空間 / FQCN / コマンド: Illuminate\Support\Collection::transform
  • 関連: map / mapInto / mapSpread / values / each
  • 変更履歴: 旧来からのメソッド。mapとの違い(破壊的)に注意。

要点(TL;DR)

  • 何に使うか:全要素をコールバックで変換して元のコレクション自体を書き換える
  • 最低限の使い方$c->transform(fn ($v, $k) => /* 変換 */);
  • よくある罠
    • mapと違い破壊的(同じインスタンスを書き換え)
    • キーは保持。添字を詰めたいならvalues()を併用
    • LazyCollectionは基本非推奨(遅延処理にはmapを使う)

概要

transformは、各要素にコールバックを適用し、その結果で元のコレクションの要素を置き換えます
mapの“非破壊”版に対し、transformは“破壊的”で、同じ変数を後段でも使う場面では副作用に注意します。キーは保持されるため、連番が必要ならvalues()で再採番します。

構文 / シグネチャ

public function transform(callable $callback): static

引数(表)

引数必須既定値説明
$callbackcallable(mixed $value, mixed $key): mixed各要素を受け取り、置き換える値を返す
  • 戻り値Collection同一インスタンス
  • 例外/副作用:元のコレクション内容が直接変更される(共有参照に注意)

使用例

最小例

<?php

use Illuminate\Support\Collection;

$prices = collect([100, 200, 300]);

$prices->transform(fn ($p) => (int) round($p * 1.1)); // 破壊的
// $prices は [110, 220, 330]

キー保持の例

<?php

$stock = collect(['AAPL' => 180, 'MSFT' => 420]);

$stock->transform(fn ($v, $symbol) => $symbol . ':' . $v);
// キーは ['AAPL', 'MSFT'] のまま

実務例(Eloquent→API用DTOへ)

<?php

use App\Models\User;

$users = User::where('active', true)->get(); // Collection<App\Models\User>

// 同じ $users を API用配列に“上書き”する
$users->transform(function ($u) {
    return [
        'id'        => $u->id,
        'name'      => $u->name,
        'joined_at' => $u->created_at->toDateString(),
    ];
});

return response()->json($users); // ここでモデルではなく配列の集合になっている点に注意

よくある落とし穴・注意

  • 破壊的:後続で元のモデル/オブジェクトが必要ならmapを使うか、$copy = $c->map(...);のように別変数へ。
  • キー保持:連番にしたい場合は$c->values()をチェーン。
  • LazyCollection:遅延評価ストリームではtransformよりmapを使う(transformは非遅延・一括処理向き)。
  • 型変更の副作用:モデルを配列へ変えた後に、モデル前提の処理($user->idなど)を続けると壊れる。

代替・関連APIとの比較

  • map:非破壊で新しいコレクションを返す。副作用を避けたい/チェーンで元を残したいならこちら。
  • each:返り値は元要素(変更しない)。副作用(ログ出力等)向け。
  • mapInto(Foo::class):各要素を指定クラスのインスタンスへ変換。
  • mapSpread:配列要素を引数として展開して変換。
  • values:キーをリセットして0からの連番へ。

選定基準

  • 元コレクションを上書きしたいtransform
  • 元を残したい/遅延したいmap

テスト例(Pest)

<?php

use Illuminate\Support\Collection;

it('transforms in place and keeps keys', function () {
    $c = collect(['a' => 1, 'b' => 2]);
    $id = spl_object_id($c);

    $c->transform(fn ($v) => $v * 10);

    expect($c->all())->toBe(['a' => 10, 'b' => 20])
        ->and(spl_object_id($c))->toBe($id); // 同一インスタンス
});

コレクション特性(カテゴリ規約)

  • チェーン可否:可(同一インスタンスを返す)
  • 破壊的/非破壊破壊的
  • キー保持保持する
  • LazyCollection非推奨(遅延処理はmapを使用)
  • 計算量:O(n)

入出力対応サンプル

入力変換出力
[1,2,3]*2[2,4,6](キー0,1,2のまま)
['a'=>1,'b'=>2]+10['a'=>11,'b'=>12](キー維持)

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

症状/エラー原因対処
Call to undefined method transform配列に対して呼んでいる先にcollect($arr)でコレクション化
モデルのプロパティ参照が壊れたtransform後に要素を配列へ変換してしまった非破壊のmapを使う/別変数に代入
連番にしたいのにキーが詰まらないtransformはキーを保持する後続でvalues()を呼ぶ

参考リンク

レン (Wren)

こんにちは。レンです。

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

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

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

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

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

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