LaravelのCollectionパッケージでPHPの配列操作を劇的に快適にする

こんにちは、池田です。最近家の鍵をsesame4というスマートロックにしました。鍵の向きを考えずにスマートフォンをかざすだけでドアが開くというのは、スマートフォンの充電端子がType-Cになったときと、駅の改札を交通系ICで通れるようになったときを合わせたような感動があります。まあどっちも昔のことで大して覚えていないので、適当言ってるだけなんですが。

本題

さて、皆さんはこの世で最も邪悪なものを知っていますか。そう、PHPでの配列操作のやりにくさですね。どれだけ配列操作がやりにくいかについては、以下の記事を読むのが良いと思います。
PHPを使いもせずDISってる君達へ 
特に記事のPHP Tips 5 : array_filterが歯抜けになるのに気をつけようの現象には、
自分「よし、配列をフィルタして最初の値を取ろう!」
array_filter([1,2,3], fn(int $num) => $num > 1)[0]
PHP「だめだよ」
自分「???」
理由:array_filterされた配列は[1 => 2, 2 => 3]になっており、0のキーは存在しないので取れないから
と何度も苦しめられました。さすがに学習した今でもこの挙動に関しては納得できず、思い出す度にFワードが出そうになります。会社のテックブログじゃなければ出してます。
また、連続で配列操作関数を使用した際のネストの深さ、読みにくさもピカイチです。こちらは先程の記事で一番最初に紹介されてますね。
これは Symfony という素晴らしいフレームワークを使っていても、如何ともし難いものがありました。先程の記事にもあったように、Symfonyでは配列をラップしたDoctrineの Collectionクラス が存在するんですが、メソッドの数が痒い所に手が届かない感じで(ソートができない!)(フラットにできない!)(ユニークにできない!)、複雑な配列操作をしようとするなら一度ネイティブの配列に戻すことが必要になります。なんか気持ち悪いですね。継承してオレオレ実装もあまりしたくありません。絶対バグを生み出すので。
ならばどうすれば良いのか……?ここで本題です。LaravelのCollectionパッケージを使いましょう。

何が良いのか

公式ページ にアクセスして、メソッド一覧を見てください。たくさんのメソッドありますね。131個あるらしいです。これだけ数があるということは、ニーズにあったメソッドも存在する可能性が高いということです。
例えば、先程挙げた3個の「ソート」「フラット」「ユニーク」は全て用意されたメソッドで可能です。また、無駄にネストを深くする必要もありません。
collect([1, [2, 3, [4, 2]]])
  ->flatten()
  ->unique()
  ->sort();
上記のように、非常にシンプルな記述をすることが可能です。
中でも、私がイチオシのメソッドは mapWithKeys です。皆さんも幼稚園くらいの頃に「以下のように連想配列に変換したいな……」と考えたことがあると思います。
↓これを
[
    [
        'name' => 'John',
        'department' => 'Sales',
        'email' => 'john@example.com',
    ],
    [
        'name' => 'Jane',
        'department' => 'Marketing',
        'email' => 'jane@example.com',
    ]
]
↓こうする
[
    'john@example.com' => 'John',
    'jane@example.com' => 'Jane',
]
ネイティブの配列操作関数でやるなら、恐らくarray_reduceでやる必要があると思います。ですが読みにくくなるので、使わないに越したことはありません。LaravelのCollectionを使えば以下のように簡単に変換することができます。
$collection = collect([
    [
        'name' => 'John',
        'department' => 'Sales',
        'email' => 'john@example.com',
    ],
    [
        'name' => 'Jane',
        'department' => 'Marketing',
        'email' => 'jane@example.com',
    ]
]);

$keyed = $collection->mapWithKeys(function ($item, $key) {
    return [$item['email'] => $item['name']];
});

$keyed->all();

/*
    [
        'john@example.com' => 'John',
        'jane@example.com' => 'Jane',
    ]
*/
別の言語だとJavaScriptは結構配列操作がやりやすいと思っているんですが、それでもこの変換をここまでシンプルにはできなかったと思うので、mapWithKeysには驚きました。 しかし、中にはLaravelを使っていない人もいるでしょう。Laravelのパッケージをまるごと入れてCollectionだけ使うしかないのでしょうか。当然そんなことはありません。以下のコマンドでこれだけ(+α)導入可能です。
composer require illuminate/support
これにより、Symfony環境であってもLaravelのCollectionの素晴らしさを享受することができます。
……え、フレームワーク使ってない?Composerなんてない?……それは……その……どうすればいいんでしょうね……?

まとめ

  • PHPネイティブの配列操作はやりにくい
  • LaravelのCollectionパッケージを使えば途端にやりやすくなる
  • 単体(+α)導入も可能