フルスタックエンジニアのノウハウ
2022.02.26    2022.11.26

無名関数(クロージャ)とは?

この記事の動画版はこちら(画像クリックでYoutubeに飛びます)

チャンネル登録お願いします!


無名関数とは?


まず、簡単に説明すると

無名関数とは、関数名を指定せずに作成出来る関数のことです。



function calc($num1, $num2)
{
    // 引数1と引数2を足して$sub_totalに入れる
    $sub_total = $num1 + $num2;

    // $sub_totalを戻り値として返す
    return $sub_total;
};

通常、関数を作る際は、このようにfunctionの後に関数名を指定して作成します。

このように作成しておくことで、後からこの関数名をコールするだけで呼び出せるようになります。

echo calc(1, 2);

ただ、例えば「コールバック関数」のように、後から再利用することなく、その場限りだけで使用したいような関数の場合は、わざわざ名前を付ける必要がありません。

そういった場合は、このように

$result = check_array($before_array,
    function ($v) {
        return $v % 3 === 0;
    }
);

functionの後に関数名を指定せずに、関数を定義することが出来ます。
これが「無名関数」です。


その場限りで使う関数に、わざわざ他と被らない分かりやすい名前を考えなくて良いというメリットがある訳ですね。

ちなみに、コールバック関数については、こちらで詳しく解説していますので、コールバック関数というものがよく分からないという場合は、こちらも是非学習してみてください。

関連記事

コールバック関数とは?どういう時に使うの?


関数自体を変数に入れておくことも出来る


無名関数は、関数自体を変数に入れておくことも出来ます。

このようにしておくと、$calc_funcという変数の中には、関数自体が入っていますので

$calc_func = function ($num1, $num2) {
    // 引数1と引数2を足して$sub_totalに入れる
    $sub_total = $num1 + $num2;

    // $sub_totalを戻り値として返す
    return $sub_total;
};

このように指定することで関数を実行させることが出来ます。

echo $calc_func(1, 2); ⇒「3」と表示される。
echo $calc_func(5, 3); ⇒「8」と表示される。

先程のコールバック関数の例も、このように関数を変数に入れておき

$callback = function ($v) {
    return $v % 3 === 0;
};

その変数をコールバック関数に指定するといったことも可能です。

$result = check_array($before_array, $callback);


クロージャとは?


無名関数も、通常の関数と同じように引数を受け取って処理を行うことが出来ます。

$calc_func = function ($num1, $num2) {
    // 引数1と引数2を足して$sub_totalに入れる
    $sub_total = $num1 + $num2;

    // $sub_totalを戻り値として返す
    return $sub_total;
};

この例では、num1とnum2という引数を受け取って、それらを足し算し、$sub_totalという変数に入れて、それを返却しています。

また、通常の関数の中では、その関数の中で定義されたローカル変数か、引数で与えられた変数にしかアクセスすることが出来ません。

例えば、このように書いても、外側にある「$total」という変数には、関数の中からはアクセスすることが出来ないため

$total = 1000;

$calc_func = function ($num1, $num2) {
    // 引数1と引数2を足して$sub_totalに入れる
    $sub_total = $num1 + $num2;

    // $totalに$sub_totalを足して戻り値として返す
    return $total + $sub_total;
};

このように呼び出したとしても、最後の行の「$total + $sub_total」の$totalの部分は0となり、$sub_totalの「3」という結果だけが出力されます。

echo $calc_func(1, 2);⇒「3」と表示される。

しかし、「use」というキーワードを指定することで、関数の外側にある変数を参照させることも出来ます。

このようにすると、関数を定義した時点での$total変数の値が参照出来るようになり

$total = 1000;

$calc_func = function ($num1, $num2) use ($total) {
    // 引数1と引数2を足して$sub_totalに入れる
    $sub_total = $num1 + $num2;

    // $totalに$sub_totalを足して戻り値として返す
    return $total + $sub_total;
};

結果は、1000+3の「1003」となります。

echo $calc_func(1, 2);⇒「1003」と表示される。

ちなみに、このようにして続けてもう1回実行すると、結果は、1000+8の「1008」になります。
echo $calc_func(5, 3);⇒「1008」と表示される。

$totalの値は、1回目の実行結果が反映されず、あくまで関数を定義した時点での値である「1000」が毎回参照されるという訳ですね。

ちなみに、useで指定する際に、このように変数の頭に「&」を付けると

$total = 1000;

$calc_func = function ($num1, $num2) use (&$total) {
    // 引数1と引数2を足して$sub_totalに入れる
    $sub_total = $num1 + $num2;

    // $totalに$sub_totalを足して戻り値として返す
    return $total + $sub_total;
};

定義した時点の固定値ではなく、$totalに対して行われた変更が反映されるようになります。

この方式を「参照渡し(またはリファレンス渡し)」と言います。


例えば、1回目の実行結果を$total変数に上書きして

// 1回目の実行で$totalを更新($total=1003)
$total = $calc_func(1, 2);

// ⇒1003と表示される。
echo $total;

再度実行すると、変更内容が反映されています。

// 2回目の実行(⇒1011と表示される)
echo $calc_func(5, 3);

このように、無名関数を宣言した時点で、外部にある特定の変数を「囲い込む」ことが出来ます。

この仕組みを「クロージャ」と言います。


クロージャを使用することで、関数内で定義されたローカル変数や引数だけでなく、外部の変数も参照することが出来るというメリットがある訳ですね。


まとめ


・無名関数とは、関数名を指定せずに作成出来る関数のこと
・コールバック関数など、その場限りで使う関数に、わざわざ名前を付けなくて良いというメリットがある
・無名関数自体を変数に入れて管理することも出来る
・クロージャを使うと、関数を定義した時点での外部変数を参照させることが出来る
・変数の頭に「&」を付けると、参照渡しとなり、外部変数の変更が反映されるようになる


おすすめ記事