array_map/array_filter/array_reduceを使いこなす
array_map・array_filter・array_reduceは、配列を変換・絞り込み・集約するための関数です。foreachでループを書かなくても、処理の意図をそのまま表現できる書き方です。
PHPの配列を扱うとき、いまだにforeachでゴリゴリ書いている人を見かけます。悪くはないんですが、array_map・array_filter・array_reduceを覚えると、意図が一目で伝わるコードになります。今日はこの3つの実務的な使い分けの話です。
変換はarray_map
「各要素を別の形に変換する」ならarray_mapです。ループ変数や一時配列を用意する必要がありません。
$users = [['name' => '田中'], ['name' => '佐藤']];
$names = array_map(fn($u) => $u['name'], $users);
// ['田中', '佐藤']
元の配列は変更されず、新しい配列が返る点がポイントです。副作用がないので、後から読んだときに安心できます。
絞り込みはarray_filter
「条件に合う要素だけ残す」ならarray_filterです。
$numbers = [1, 2, 3, 4, 5, 6];
$even = array_filter($numbers, fn($n) => $n % 2 === 0);
// [1 => 2, 3 => 4, 5 => 6]
ここで注意したいのが、array_filterはキーを保持することです。上の結果のキーが0,1,2ではなく2,4になっているのが分かります。連番に振り直したいならarray_values()で包んでください。ここは地味にハマるポイントです。
集約はarray_reduce
「配列を1つの値にまとめる」ならarray_reduceです。合計や最大値、あるいは配列を連想配列に組み替えるときに使えます。
$cart = [
['price' => 500, 'qty' => 2],
['price' => 300, 'qty' => 1],
];
$total = array_reduce($cart, fn($carry, $item) => $carry + $item['price'] * $item['qty'], 0);
// 1300
第3引数が初期値です。これを忘れるとnullスタートになって型エラーの原因になるので、必ず明示しておくのがおすすめです。
まとめ
変換ならmap、絞り込みならfilter、集約ならreduce。この対応を頭に入れておくと、foreachの中で何をやっているのか読み解く手間がなくなります。ただし何でもかんでもこれらに置き換えると逆に読みにくくなることもあるので、複雑な処理は素直にforeachにする、くらいの温度感がちょうどいいと思います。
よくある質問
Q. array_filterの結果でキーが飛び飛びになってしまいます。
A. array_filterは元のキーを保持する仕様です。連番に振り直したいときはarray_values()で包んでください。
Q. array_reduceの初期値(第3引数)は省略できますか。
A. 省略するとnullスタートになり、加算などで型エラーの原因になります。合計なら0、といった初期値を明示しておくのがおすすめです。