PHP を嫌う人たちはさまざまな理由で常に PHP を攻撃してきましたが、最も攻撃されやすい理由の 1 つは、コードの見苦しさです。コードのクリーンさや「美しさ」が重要であることに同意しない人もいるかもしれませんが、コードベースを長期にわたって維持することになると、読みやすいコードを使用することでチームの時間を大幅に節約できます。
Apple に在籍中、私は社内関係者が使用する金融アプリケーションのエコシステムを開発しました。長年にわたり、私は新しい開発者をツールに継続的に参加させ、一般的なメンテナンスや機能強化を支援してきました。そのときに得た大きな教訓の 1 つは、コードを自然言語で読めることがいかに重要であるかということです。
興味深いことに、ほとんどのコードは、かなりの部分を読み通してから最初に戻って、何が起こっているのかを完全に理解する必要があるような方法で書かれています。コードを書くときに、より表現力豊かな言語や API を使用すると、新しい開発者のオンボーディングと立ち上げ時間を大幅に短縮できます。
ここでコレクションが活躍します。Laravel コレクションは、複雑な配列のトラバーサルを非常に読みやすく理解しやすいものにします。コードは、「この配列を a で始まる単語だけにフィルターし、コスト額を行にマッピングし、最後にこれをすべてのコストの合計に減らす」というコマンド チェーンになります。より表現力豊かな言語でコードを書くことの重要性を過小評価するのは簡単ですが、一度それを習慣にすると、他の方法が受け入れられるとは考えにくくなります。
もちろん、読みやすさはパフォーマンスを犠牲にして得られるものではないため、常に適切な選択を行い、適切な場合にのみ読みやすさを優先することが重要です。舞台裏で何が起こっているかを常に理解し、ソリューションへのアプローチ方法によってどのようなトレードオフが発生するかを十分に認識する必要があります。読みにくいソリューションよりも 1 秒も長くかかるのであれば、コードが読みやすくても何の役にも立ちません。
PHP の配列とコレクションを詳しく見て、両者のパフォーマンスを比較してみましょう。
Laravel コレクションを使用する最大の利点の 1 つは、メソッドの連鎖を可能にする流暢な構文です。これにより、一時変数や複雑にネストされた関数呼び出しを必要とせずに、複数の操作を連続して実行できるため、クリーンで読みやすいコードになります。
以下では、よく使用される配列操作関数のいくつかを比較し、非常に簡単な例で PHP とコレクションを比較してみましょう。
PHP の
array_filter($data, function($row) { return substr($row, 0, 1) === "a"; });
コレクション
$data->filter(function($row) { return substr($row, 0, 1) === "a"; });
PHP の
array_search(function($row) { return substr($row, 0, 1) === "a"; }, $data);
コレクション
$data->search(function($row) { return substr($row, 0, 1) === "a"; });
PHP の
array_map(function($row) { return "test"; }, $data);
コレクション
$data->map(function($row) { return "test"; });
PHP の
sort($data);
コレクション
$data->sort();
PHP の
foreach($loop as $item) { $doSomething = true; }
コレクション
$data->each(function($row) { return "test"; });
PHP の
array_reduce($data, function($carry, $row) { return $carry + strlen($row); });
コレクション
$data->reduce(function($carry, $row) { return $carry + strlen($row); });
PHP の
array_splice($data, count($data)/2);
コレクション
$data->splice(count($data)/2);
みんなで一緒に(PHP)
$data = array_filter($data, function($row) { return substr($row, 0, 1) === "a"; }); $data = array_search(function($row) { return substr($row, 0, 1) === "a"; }, $data); $data = array_map(function($row) { return "test"; }, $data); sort($data); foreach($loop as $item) { $doSomething = true; } $sum = array_reduce($data, function($carry, $row) { return $carry + strlen($row); });
みんなで一緒に(コレクション)
$sum = $data->filter(function($row) { return substr($row, 0, 1) === "a"; })->search(function($row) { return substr($row, 0, 1) === "a"; })->map(function($row) { return "test"; })->sort() ->each(function($row) { return "test"; })->reduce(function($carry, $row) { return $carry + strlen($row); });
比較
このように単純なアプローチでは、個々の関数の読みやすさに大きなトレードオフはないように見えますが、すべての関数を 1 つの配列に適用する必要がある例を考えると、コレクション内でチェーンされたメソッドを使用する方が簡潔で読みやすいことがはっきりとわかります。
変数を常に上書きして最後に出力用の新しい変数を設定する代わりに、目的の出力が得られるまですべてのコマンドを単純に連鎖させることができます。コードが複雑になるほど、コレクションは間違いなく読みやすくなります。
私は上記の例を参考にして、コレクションのパフォーマンスが標準の PHP 関数よりも優れているか劣っているかを判断するためにいくつかのテスト データを生成しました。
各配列には100,000 個のランダムな文字列が項目として含まれており、各関数を 100 回実行しました。最後に、すべての応答時間の平均を計算しました。
最終結果は以下の通りです。
========== Tests Complete (ms) ========== php filter: 5.07 collect filter: 6.49 ======================= php search: 0.79 collect search: 0 ======================= php map: 3.45 collect map: 4.18 ======================= php sort: 25.27 collect sort: 11.18 ======================= php each: 1.03 collect each: 6.96 ======================= php reduce: 2.78 collect reduce: 7.75 ======================= php splice: 1 collect splice: 0.74 =======================
明らかにわかるように、コレクションによって可読性は大幅に向上しますが、いくつかの重要な領域ではパフォーマンスが大幅に低下します。
Filter 、 Map 、 Foreach 、 Reduce はすべて、標準の PHP 関数を使用すると高速になります。 ForeachとReduce には、実は非常に大きな違いがあります。 Search 、 Sort 、 Splice はすべて Collections が勝者であり、 Sort は実に大幅な時間節約になります。
また、構築された配列から各コレクションを作成する必要があることにも留意することが重要です。これにより、コレクションの設定にわずかなオーバーヘッドが追加されますが、そのわずかな追加作業と時間でも、結果は非常に明確になります。
私の意見では (これはこれらの結果に基づく意見にすぎませんが)、パフォーマンスが大きな懸念事項である場合、 Foreachループには標準の PHP 機能を使用することをお勧めします。Reduceのニーズにもおそらく同じことが当てはまります。大規模なデータセットで並べ替えを行う必要がある場合、明らかに Collections が適切な方法です。残りは非常に近いため、本当に個人的な好みのように感じられます。
その点では、コレクションの方が読みやすく、維持しやすいと言えます。
もちろん、この情報を参考にして、自分自身で十分な情報を得た上で決定する必要がありますが、私と同じような人であれば、上記の関数の多くにコレクションを組み込むことになると思います。しかし、今後は、適切な場所で→each
と→reduce
の使用を減らすつもりです。