があることに注意してください。
- 無名関数の構文
- function( [ 引数 ] ... ) { 文 };
PHP以外の言語では、グローバルスコープの変数に関数内部からもいつでもアクセスできるようになっています。PHPの場合は$GLOBALS変数を使用するかglobal宣言してから利用しなければなりません。無名関数の中からも同じような制限があります。
無名関数の中から無名関数が実行されるスコープ内の変数を使用する場合には、“use”文で使用を宣言しなければなりません。
- use文を利用する場合の無名関数の構文
- funciton( [ 引数 ] ... ) use ( [ 変数 ] ... ) { 文 };
多少面倒に思うかも知れませんが、明示的に指定した変数以外はアクセスできないので、誤って意図しない変数を書き換えてしまったり、利用してしまうことを防ぐことができます。
無名関数は関数名が無いので、変数に格納するか、関数の引数として直接渡します。
これだけでは何が便利なのかさっぱり分からないですが、使い方だけは分かったと思います。
の部分が無名関数の定義です。無名関数は直接パラメータとしてほかの関数に渡すことが出来ます。
無名関数が無いPHP 5.2場合、パラメータとして渡している
を別の関数として定義した上で、変数関数としてarray_walk関数に渡さなければなりません。
あまり、複雑でないのでわかりづらいかも知れませんが、無名関数を利用すると簡潔に記述できることが分かります。
無名関数を使うと、クラスを使ったオブジェクト指向設計を行わなくても、一つの関数に複数の動作を行わせることも簡単です。
変数関数に書き換えると次のようになります。
どちらも全く同じことができますが、大きな違いがあります。変数関数の場合、名前付き関数として定義しなければならないため、名前空間を使用していしまいます。処理する変数が数値でなく配列の場合は要素すべてを2乗したりインクリメントしたりする、という関数を新たに追加する場合に‘square’という関数名は既に使われているので使えません。
‘square_array’などのように別の名前を付ければよいのですが、次々に新しい名前を付けなければならないかも知れません。
また、uasort関数の比較を行うコールバック関数のように、その場限りのコールバック関数に名前を付けるのは面倒です。
この例では多次元配列ですが、要素がオブジェクトである場合もソートしたいかも知れません。名前付き関数を定義した上で利用しなければならない仕様は、無名関数に慣れているプログラマに取っては苦痛でしかありません。
次はよりクロージャの便利さが分かる、関数が定義されたコンテクストの変数(レキシカル変数)を利用したクロージャの利用例です。便利さ分かる例として、配列に格納された商品に消費税を付けて合計するプログラムを作ってみます。
PHPはクロージャ(レキシカル変数)をサポートしていなかったので、array_walk関数の第3引数に任意のデータを渡せるようになっていました。PHPがクロージャをサポートしていれば必要なかった引数です。
実はこのコードではクロージャを利用した例のように動作しません。コールバック関数のuser_data引数が参照として渡されていないからです。この結果、合計が計算されていません。同様の結果を得るにはグローバル変数を利用しなければなりません。
クロージャ(レキシカル変数)を利用した例とクロージャを利用しない例を見比べれば、クロージャを利用したほうが簡潔でコードも分かりやすく、不必要な関数で名前空間も利用しないことが分かります。
クロージャ(無名関数)を使用したことがない方は、慣れるまでは名前が無いことに違和感があるかも知れません。しかし、クロージャは簡潔かつ柔軟なコードを記述するために便利なので覚えておくとよいと思います。
制限付きgoto文
PHPにはプログラムの実行を自由な場所に移動するgoto文がサポートされていませんでした。goto文の乱用は簡単に理解不能なプログラムを作ってしまうからです。
しかし、goto文を利用するとエラー処理や特定の条件を満たした場合にループを抜ける処理が簡潔に記述できます。goto文があるほうが分かりやすく記述できるのです。
Visual Baiscでプログラミングをした経験がある方であれば、Visual Basicではエラーが発生した場合にgoto文でエラー処理のコードまでジャンプするようなコードをよく見かけていると思います。PHP 5.3からは同じようなエラー処理が可能になります。
goto文の使い方
- 構文
- goto ラベル;
goto文の使い方は説明するまでもないと思います。以下にサンプルコードを書いておきます。
goto文によりコードが大幅に読みやすくなる場合以外は極力利用しないようにするほうが良いでしょう。上の例のような単純にループから抜け出る場合は、break文が使用できます。
ループ処理の例外処理はほとんどの場合、break文、continue文で分かりやすく処理できます。goto文を利用するよりも、まずbreak文、continue文の利用を考えるようにしたほうが良いでしょう。
次回はPHP 5.3で追加された機能と、仕様変更について取り上げます。
- 参考文献
- PHP マニュアル
- PHP 5.2 to 5.3マイグレーションガイド
- PHP 5.3ソース