アロー関数(fn)
| 対応: | PHP 7.0(2015) |
|---|
短い無名関数をより簡潔に書くには『PHP』7.4で追加されたアロー関数(『fn』キーワード)が便利です。従来の『function』キーワードを使ったクロージャと異なり、外部スコープの変数を『use』なしで自動的にキャプチャできるため、コールバックの記述をすっきりとまとめられます。
構文
// アロー関数の基本構文
$関数名 = fn(引数) => 式;
// 引数なし
$関数名 = fn() => 式;
// 引数に型ヒントと戻り値型を指定できます
$関数名 = fn(型 $引数): 戻り値型 => 式;
// 従来のクロージャ(比較用)
$クロージャ = function(引数) use ($外部変数) {
return 式;
};
アロー関数とクロージャの違い
| 項目 | クロージャ(function) | アロー関数(fn) |
|---|---|---|
| 外部変数のキャプチャ | 『use ($変数)』で明示的に宣言する必要があります。 | 外部スコープの変数を自動的にキャプチャします。『use』は不要です。 |
| キャプチャの種類 | 値渡し(デフォルト)と参照渡し(&)を選択できます。 | 値渡しのみです。参照渡しはできません。 |
| 本体の記述 | 複数の文を『{ }』の中に書けます。 | 単一の式のみです。『return』は書きません(自動的に返されます)。 |
| 複数行の処理 | 可能です。複雑な処理を書けます。 | 不可能です。1つの式に収まらない処理には向きません。 |
| 用途 | 複雑な処理や副作用を伴う処理に向いています。 | 変換・フィルタなど、値を返すシンプルな処理に向いています。 |
サンプルコード
アロー関数の基本と外部変数の自動キャプチャ
arrow_basic.php
<?php
// Steins;Gateのキャラクター名を使ったアロー関数の基本例です
// ---- クロージャ(useが必要) ----
$labName = "未来ガジェット研究所";
// クロージャでは外部変数 $labName を use で明示的にキャプチャします
$greetClosure = function(string $name) use ($labName): string {
return $name . "は" . $labName . "のメンバーです。";
};
echo $greetClosure("岡部倫太郎") . "\n";
echo $greetClosure("椎名まゆり") . "\n";
// ---- アロー関数(useが不要) ----
// アロー関数は外部変数を自動的にキャプチャします
// $labName を use なしで直接参照できます
$greetArrow = fn(string $name): string => $name . "は" . $labName . "のメンバーです。";
echo $greetArrow("阿万音鈴羽") . "\n";
echo $greetArrow("桐生萌郁") . "\n";
実行すると次のように出力されます。
php arrow_basic.php 岡部倫太郎は未来ガジェット研究所のメンバーです。 椎名まゆり は未来ガジェット研究所のメンバーです。 阿万音鈴羽は未来ガジェット研究所のメンバーです。 桐生萌郁は未来ガジェット研究所のメンバーです。
array_map / array_filter との組み合わせ
arrow_array_map_filter.php
<?php
// Steins;Gateのキャラクターデータを使って
// array_map / array_filter とアロー関数を組み合わせる例です
$characters = [
["name" => "岡部倫太郎", "divergence" => 1.048596, "isMember" => true],
["name" => "牧瀬紅莉栖", "divergence" => 1.130205, "isMember" => true],
["name" => "椎名まゆり", "divergence" => 1.048596, "isMember" => true],
["name" => "阿万音鈴羽", "divergence" => 1.048596, "isMember" => true],
["name" => "ビルゲイツ10世", "divergence" => 0.337187, "isMember" => false],
];
// array_map: 各キャラクターの名前にラベルを付けた文字列の配列を作ります
// アロー関数で各要素を変換します
$labels = array_map(
fn($c) => $c["name"] . "(世界線: " . $c["divergence"] . ")",
$characters
);
echo "--- 全キャラクター ---\n";
foreach ($labels as $label) {
echo $label . "\n";
}
// array_filter: ラボメンだけを抽出します
// アロー関数でフィルタ条件を指定します
$members = array_filter(
$characters,
fn($c) => $c["isMember"] === true
);
echo "\n--- ラボメンのみ ---\n";
foreach ($members as $member) {
echo $member["name"] . "\n";
}
// 外部変数を自動キャプチャする例です
// 特定の世界線のキャラクターだけを抽出します
$targetDivergence = 1.048596;
$filtered = array_filter(
$characters,
// アロー関数は外部変数 $targetDivergence を use なしで参照できます
fn($c) => $c["divergence"] === $targetDivergence
);
echo "\n--- 世界線 " . $targetDivergence . " のキャラクター ---\n";
foreach ($filtered as $c) {
echo $c["name"] . "\n";
}
実行すると次のように出力されます。
php arrow_array_map_filter.php --- 全キャラクター --- 岡部倫太郎(世界線: 1.048596) 牧瀬紅莉栖(世界線: 1.130205) 椎名まゆり(世界線: 1.048596) 阿万音鈴羽(世界線: 1.048596) ビルゲイツ10世(世界線: 0.337187) --- ラボメンのみ --- 岡部倫太郎 牧瀬紅莉栖 椎名まゆり 阿万音鈴羽 --- 世界線 1.048596 のキャラクター --- 岡部倫太郎 椎名まゆり 阿万音鈴羽
アロー関数のネストと外部変数の多段キャプチャ
arrow_nested.php
<?php
// アロー関数はネストした場合も外部スコープの変数を自動キャプチャします
// クロージャではネストするたびに use の宣言が必要ですが、アロー関数は不要です
$worldLine = "β世界線";
$organization = "SERN";
// 外側のアロー関数が $worldLine をキャプチャし、
// 内側のアロー関数は $worldLine と $organization の両方をキャプチャします
$getInfo = fn(string $name) =>
fn(int $labMemNo): string =>
"ラボメン" . $labMemNo . "号 " . $name
. "(" . $worldLine . " / " . $organization . ")";
// 外側の関数を呼び出してから内側の関数を呼び出します
$okabeInfo = $getInfo("岡部倫太郎");
echo $okabeInfo(1) . "\n";
$kurisu = $getInfo("牧瀬紅莉栖");
echo $kurisu(4) . "\n";
// 比較: クロージャで同じ処理を書くと use が二重に必要です
$getInfoClosure = function(string $name) use ($worldLine, $organization) {
return function(int $labMemNo) use ($name, $worldLine, $organization): string {
return "ラボメン" . $labMemNo . "号 " . $name
. "(" . $worldLine . " / " . $organization . ")";
};
};
$mayuri = $getInfoClosure("椎名まゆり");
echo $mayuri(2) . "\n";
実行すると次のように出力されます。
php arrow_nested.php ラボメン1号 岡部倫太郎(β世界線 / SERN) ラボメン4号 牧瀬紅莉栖(β世界線 / SERN) ラボメン2号 椎名まゆり(β世界線 / SERN)
使える場面と制限事項
| 項目 | 内容 |
|---|---|
| 適した用途 | 『array_map』『array_filter』『array_reduce』『usort』などのコールバック引数として、値の変換・抽出・比較をシンプルに記述する場面に向いています。 |
| 単一式の制限 | 本体は単一の式のみ書けます。複数の文や条件分岐が必要な場合はクロージャを使用してください。 |
| 参照キャプチャ不可 | 外部変数は値渡しのみキャプチャされます。外部変数の値をアロー関数内から変更することはできません。変更が必要な場合はクロージャで『use (&$変数)』を使用してください。 |
| 再帰には不向き | アロー関数に名前を付けて自分自身を呼び出す再帰は、変数経由では可能ですが可読性が低くなります。再帰処理には通常の名前付き関数を使用してください。 |
| 戻り値 | 式の評価結果が自動的に返されます。明示的な『return』は書きません(書くと構文エラーになります)。 |
| PHP バージョン | PHP 7.4 以降で使用できます。PHP 7.3 以前の環境では動作しません。 |
よくあるミス
アロー関数の本体に複数の文を書こうとする
アロー関数の本体には単一の式しか書けません。複数の文を書こうとすると構文エラーになります。
ng_arrow_multi.php
<?php
$labName = "未来ガジェット研究所";
// アロー関数の本体に複数の文を書こうとしている(構文エラー)
$greet = fn(string $name) => {
$label = $name . "は" . $labName . "のメンバーです。";
return $label;
};
実行すると次のように出力されます。
php ng_arrow_multi.php
Parse error: syntax error, unexpected token "{" in ng_arrow_multi.php on line 5
複数の文が必要な場合はクロージャ(function キーワード)を使います。
ok_arrow_multi.php
<?php
$labName = "未来ガジェット研究所";
// 複数の文が必要な場合はクロージャを使う
$greet = function(string $name) use ($labName): string {
$label = $name . "は" . $labName . "のメンバーです。";
return $label;
};
echo $greet("岡部倫太郎") . "\n";
echo $greet("椎名まゆり") . "\n";
実行すると次のように出力されます。
php ok_arrow_multi.php 岡部倫太郎は未来ガジェット研究所のメンバーです。 椎名まゆり は未来ガジェット研究所のメンバーです。
アロー関数の本体に return を書く
アロー関数では式の評価結果が自動的に返されます。明示的に return を書くと構文エラーになります。
ng_arrow_return.php
<?php $members = ["岡部倫太郎", "牧瀬紅莉栖", "阿万音鈴羽"]; // return を書くと構文エラーになる $upper = array_map(fn($name) => return strtoupper($name), $members);
実行すると次のように出力されます。
php ng_arrow_return.php Parse error: syntax error, unexpected token "return" in ng_arrow_return.php on line 5
アロー関数の本体には式のみを書きます。return は不要です。
ok_arrow_return.php
<?php
$divergences = [1.048596, 1.130205, 0.337187];
// return は不要。式をそのまま書く
$rounded = array_map(fn($d) => round($d, 2), $divergences);
foreach ($rounded as $v) {
echo $v . "\n";
}
実行すると次のように出力されます。
php ok_arrow_return.php 1.05 1.13 0.34
アロー関数内から外部変数を書き換えようとする
アロー関数がキャプチャする外部変数は値渡しです。ループ内でカウンタを加算するなど、外部変数を書き換えようとしても元の変数には反映されません。
ng_arrow_modify.php
<?php $count = 0; $members = ["岡部倫太郎", "牧瀬紅莉栖", "椎名まゆり"]; // アロー関数内で $count を変更しようとしているが反映されない array_walk($members, fn($name) => $count++); echo $count . "\n"; // 0 のまま
実行すると次のように出力されます。
php ng_arrow_modify.php 0
外部変数を書き換えたい場合はクロージャで use (&$変数) を使います。
ok_arrow_modify.php
<?php
$count = 0;
$members = ["岡部倫太郎", "牧瀬紅莉栖", "椎名まゆり"];
// 外部変数を書き換えるには参照渡しのクロージャを使う
array_walk($members, function($name) use (&$count) {
$count++;
});
echo $count . "\n"; // 3
実行すると次のように出力されます。
php ok_arrow_modify.php 3
概要
アロー関数(『fn』キーワード)はPHP 7.4で追加された短縮構文で、外部スコープの変数を『use』なしで自動キャプチャできる点が最大の特徴です。ただし本体は単一の式のみで、外部変数への参照渡しはできません。この制約があるため、複雑な処理や副作用を伴う処理には従来のクロージャを使う必要があります。
『array_map』や『array_filter』のコールバックとしてアロー関数を使うと、外部変数を自然に参照しながらシンプルに書けます。また複数のアロー関数をネストした場合も、それぞれのスコープの変数が自動的にキャプチャされるため、クロージャのように多段の『use』宣言が不要です。『array_map』と『array_filter』の詳細については『array_map / array_filter』を参照してください。
アロー関数とクロージャは、どちらも「関数オブジェクト」として変数に代入したり、引数として渡したりできます。処理の内容が短く値を返すだけであればアロー関数、複数の文が必要だったり外部変数を書き換える必要があればクロージャ、というように使い分けてください。クロージャの詳細については『無名関数(クロージャ)』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。