ツイート
シェア
LINEで送る
B! はてぶでブックマーク
Pocketでブックマーク
RSSフィード

PHPにもアロー関数あるんだ。JavaScriptと似てるけど根本に違いがある。

php
イラストダウンロードサイト【イラストAC】
の画像をもとに加工しています。

アロー関数は '=>' を使った無名関数のもうひとつの書き方です。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公式ドキュメント

Class - Closure

通常の関数と同じことをパラメータでできる

アロー関数のパラメータ、戻り値は通常の関数と同じことができます。

一気にサンプルでお見せします。

アロー関数の戻り値の型宣言

$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公式ドキュメント

アロー関数

前の投稿
PHPの無名関数とクロージャは同じ扱い。元々そう思ってる人は多いけど。
PHP, Closureクラス, 無名関数(クロージャ)が返すオブジェクトの型
次の投稿

コメントを残す