• PHP
モダンなPHPコードで使用!無名関数の使い方

無名関数とは

名前の通り名前を持たない関数です

一般的には下記の通り変数に代入する方法で定義します

PHPの無名関数の基本 $greet = function($name) { return “こんにちは、{$name}さん!”; }; $greet function($name) { return “…”; } 無名関数を変数に格納して後で使用できます

useキーワードを使用し外部の変数を関数内で使用可能

無名関数は「クロージャ(閉じる)」とも呼ばれ、関数外部の変数を関数内に持ち運ぶ(閉じ込める)ことができます

【useキーワード】を使用して外部変数を取り込み

PHPのクロージャとuseキーワード 外部スコープ $message = “こんにちは” クロージャのスコープ $closure = function() use ($message) { echo $message; }; useで取り込み クロージャは外部スコープの変数を 「use」キーワードで取り込んで使用できます

PHPで無名関数だけがuseキーワードを使えるのには、言語設計上の理由があります。

なぜ無名関数だけがuseキーワードを使えるのか

  1. 言語設計の選択 基本的には「そういう設計になっている」というのが第一の理由です。PHPの設計者たちがこのような文法を選んだということになります。しかし、その背景には技術的な理由もあります。
  2. スコープとクロージャの概念 通常の名前付き関数は、定義された時点でグローバルスコープや現在の名前空間に属します。これらの関数は実行時にはそのスコープから独立して動作するよう設計されています。 一方、無名関数(クロージャ)は「関数が定義された環境の状態を取り込む」というクロージャの概念に基づいて設計されています。useキーワードはこの「状態の取り込み」のための構文です。
  3. 実行環境の違い 名前付き関数は定義された時点でコンパイルされ、実行環境から独立します。無名関数は変数に代入され、実行時に評価されるため、実行時の環境(変数など)を取り込むことができます。

技術的な理由

PHPエンジン内部での実装上の理由もあります:

  1. 静的解析と実行時解析 名前付き関数は通常、コードがパースされる際に静的に解析されます。この時点では、関数が実際に呼び出される文脈はまだわかりません。 useキーワードはしかし、特定の実行時の変数をキャプチャするものなので、静的に解析される名前付き関数では使用できないように設計されています。
  2. 変数スコープの明確化 PHPでは、名前付き関数内からは自動的にグローバル変数へアクセスできないようになっています($GLOBALSやglobalキーワード経由を除く)。これは意図しない副作用を防ぐための設計です。 useキーワードは、クロージャがアクセスできる外部変数を明示的に宣言するための仕組みであり、この変数スコープの明確化というPHPの設計哲学に沿っています。

他の言語との比較

他のプログラミング言語では異なるアプローチを取っているものもあります:

  • JavaScriptでは関数内から自動的に外部スコープの変数にアクセスできます(明示的なキーワードなし)
  • Pythonでも関数内から外部スコープの変数を参照できますが、書き換えは特別な宣言(nonlocal)が必要です
  • Rubyではブロックがレキシカルスコープのどこからでも変数にアクセスできます

PHPは明示的なスコープを好む設計哲学を持っており、useキーワードはその一環として無名関数に限定されています。

基本的には言語設計の選択ですが、それにはPHPの変数スコープに関する設計哲学が反映されているのです。

無名関数はコールバック関数としてよく使用されます

そもそもコールバック関数とは、別の関数によって「呼び戻される」という意味で、直接呼び出すのではなく、間接的な呼び出しをされます。

コールバック関数で無名関数を使用すると、コードを書く場所と近い位置に定義できるため、関連するコードがまとまり読みやすくなります

※名前付き関数の場合、関数定義がファイルの先頭箇所や、別ファイルの場合もありますからね、、🤷‍♀️

PHPの無名関数をコールバックとして使用 $numbers = [1, 2, 3, 4, 5]; $doubled = array_map(function($n) { return $n * 2; }, $numbers); // $doubled は [2, 4, 6, 8, 10] になります [1, 2, 3, 4, 5] function($n) { return $n * 2; } [2, 4, 6, 8, 10]