2012/12/22
PHP 5.3 の「無名関数」
-
-
PHP 5.3 からは、「無名関数」が利用できるようになった。必要な場所に直接関数を記述できるので、ちょっとしたデータ変更の際に、いちいち関数を定義しなくてもよくなった。
例えば、データベースから配列として取得したレコードを一気に処理するような場合
2 | $ret = array_map ( function ( $data ) { ... }, $result ); |
のようにできる。これまではたとえ一度しか利用しないような処理であっても関数として定義してやらなければならなかったので、名前の衝突や定義した場所の管理が必要だった。それに比べると、ソースのリーダビリティとメンテナンシビリティは格段に向上したと思う。
ただし、PHP の無名関数では、当該関数の中の変数スコープは当該関数定義内に限定されており、当該無名関数のすぐ外側のスコープで定義された変数を参照しても未定義扱いになってしまう。例えば、次のような場合だ。
05 | $ret = array_map ( function ( $data ){ |
08 | case 1: return $data [ 'name' ]; |
09 | default : return $data [ 'address' ]; |
この例では $result を処理する外側で $cond という変数を定義しており、その値に応じて配列を処理した結果を変えたいのだ。動的スコープをサポートする言語では上記のようなコードでも自スコープ内に未定義の変数は外部スコープに拡張して検索し動作するが、PHP では無名関数定義内の $cond は当該関数内のスコープに限定されてしまい、外部の $cond を参照することはできない。かといってグローバル変数として処理するのはリーダビリティとメンテナンシビリティを損じるのでやりたくない。
これで困って PHP のマニュアルを眺めていたら、大きなサンプルとサンプルの間にチョロっとこんなことが書いてあった。
変数を親のスコープから引き継ぐことができます。 引き継ぐ変数は、関数のヘッダで宣言しなければなりません。
で、結局 PHP の無名関数では外部参照が必要な変数は無名関数の定義時に function (...) use ($variable, &$reference, ...) { ...} のようにして、参照される変数を use(...) で宣言することで対応している。従って
05 | $ret = array_map ( function ( $data ) use ( $cond ) { |
08 | case 1: return $data [ 'name' ]; |
09 | default : return $data [ 'address' ]; |
とすることで無名関数内で外部の $cond を参照できるようになる。よかったよかった。
なお、use(...) には &$variable のように参照渡しも記述できるので、(使用の是非は別にして) 無名関数内での処理結果を外部変数に書き込んで戻すことも可能だ。