アロー関数は '=>' を使った無名関数のもうひとつの書き方です。PHP7.4で追加されました。
'function' がないので、連想配列の変形ですか? みたいに感じますが、慣れるとこっちのほうが分かりやすくなります。
ただし、関数内はreturn式の一行だけという条件付きですが。
アロー関数の書き方
アロー関数とそれと同じ処理の無名関数(クロージャ)のサンプルを並べて比較します。
無名関数・クロージャが分からない人は、まずはこちらからどうぞ。
$z = 3;
// 無名関数(クロージャ)
$test1 = function ($x, $y) use ($z) {
return $x + $y + $z;
};
$val1 = $test1(1, 2);
var_dump($val1);
// 同じものをアロー関数ですると、
$test2 = fn($x, $y) => $x + $y + $z;
$val2 = $test2(1, 2);
var_dump($val2);
int(6)
int(6)
fn (argument_list) => expr
expr: returnの式
かんたんですね?
アロー関数は『returnの1行しかないんだったら1行で書こうよ』と用意された簡潔にした無名関数の記述です。
ちなみに、JavaScriptでは 'fn' がありません。PHPもそうしてほしかったな~。
use() はいらない。自動でキャプチャされる。
クロージャでは、上位の変数をあたかも自分のものかのように参照できるんですが、PHPは use() で専用のパラメータとして受け取らないといけません。
パラメータなので、その変数値を変更しても元の変数には影響を与えない。ここがJavaScriptとちがう。
JavaScriptではクロージャ内の変更が元の変数に反映されます。
PHPのアロー関数では use() を使わないので、JavaScriptと同じように見えます。
値を変更したらどうなるか確認しましょう。
$z = 3;
$test = fn() => ++$z;
$result = $test();
var_dump($result);
var_dump($z);
int(4)
int(3)
++$z は $z + 1 してから結果を $z に代入する。でも、結果は元の $z には反映されません。
どうやらJavaScriptとはちがうままで、use() の省略形みたいですね?
ちなみに、何の文法もなしに、あたかも自分の変数かのように扱うことをPHPではキャプチャといいます。
キャプチャは『捕える』という意味ですが、変数ではなく値を捕えるという意味らしい。
無理やり2行分の処理を書いたらどうなるか?
『ほんとうに1行分しか処理が書けないのか?』
どうでもいい疑問をもっちゃったので、無理やり2行分の処理を入れてみました。
<?php
$z = 3;
$test = fn($x, $y) => $x + $y; $x + $y + $z;
$val = $test(1, 2);
var_dump($val);
PHP Warning: Undefined variable $x in /home/vagrant/php-test.php on line 5
PHP Warning: Undefined variable $y in /home/vagrant/php-test.php on line 5
int(3)
どうやら、最初のセミコロン(;)までを戻り値として使って、残りは無視しているようです。
ログには警告で無視したところの $x, $y は知らないよ? というメッセージが出ました。
最初のセミコロンまでは変数の解析が行われ、そのあとは変数を変数として認識していないみたい。
というか、よく警告で済んだな。シンタックスエラーになると思ったのに。
アロー関数のネスト
アロー関数はネストできます。アロー関数の中でアロー関数を返し、その中でアロー関数を返し、... を繰り返すこと。
$z = 3;
// アロー関数のネスト
$fn = fn($x) => fn($y) => $x + $y + $z;
// ネストしたアロー関数の実行
$result = $fn(1)(2);
var_dump($result);
// 上記はこれを1個の式にまとめている。
$closure = $fn(1);
$result2 = $closure(2);
var_dump($result2);
// これと同じ。
$func = function ($x) use ($z) {
return function ($y) use ($x, $z) {
return $x + $y + $z;
};
};
$result3 = $func(1)(2);
var_dump($result3);
int(6)
int(6)
int(6)
アロー関数のネストの驚きの機能は、$z は最下層のクロージャまでキャプチャされることです。
同じ処理を無名関数で書いたものと比べると分かる。無名関数では、最下層で使うために use() で渡して渡してを繰り返している。
ここまで来ると、1行で簡潔なアロー関数が逆に『何やってんだ?』に見えなくもない。
とくに、無名関数・アロー関数はClosureクラスのオブジェクトを返すのを意識できてないと、実行時に変数の後ろに括弧(())が増えていくごとに、括弧じゃなくて頭の中で?が増えていく。
PHP公式ドキュメント
通常の関数と同じことをパラメータでできる
アロー関数のパラメータ、戻り値は通常の関数と同じことができます。
一気にサンプルでお見せします。
アロー関数の戻り値の型宣言
$fn = fn($x): int => $x;
$result = $fn(10);
var_dump($result);
int(10)
アロー関数のパラメータの型宣言
$fn = fn(array $x) => $x;
$result = $fn([1, 2, 3]);
var_dump($result);
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
アロー関数のパラメータの初期値設定
$fn = fn($x = 20) => $x;
$result = $fn();
var_dump($result);
int(20)
アロー関数のパラメータが可変長
$fn = fn(...$args) => $args;
$result = $fn(1, 2, 3, 4, 5);
var_dump($result);
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
アロー関数のパラメータがリファレンス
$x = 3;
$fn = fn(&$x) => ++$x;
$result = $fn($x);
var_dump($result);
var_dump($x);
int(4)
int(4)
アロー関数の戻り値がリファレンス
$x = 'default';
$fn = fn&(&$x) => $x;
$refer =& $fn($x);
var_dump($refer);
$x = 'change';
var_dump($refer);
string(7) "default"
string(6) "change"
staticなアロー関数
$fn = static fn($x) => $x;
$result = $fn(30);
var_dump($result);
int(30)
staticなアロー関数は staticな無名関数と同じ動きをします。
staticな無名関数についてはこちらに書きました。
PHP公式ドキュメント