PHPの配列記法で関数オブジェクト
C++などは()をオーバーロードして関数オブジェクトを作るらしいですが、PHPでも配列記法やアロー演算子のオーバーロードが可能なので、似たような関数オブジェクトは作れそうです。
http://d.hatena.ne.jp/noopable/20090316/1237166080
ここでやった手法は、理念的なものであるのに比べて、ここでは記法的な問題を扱います。
配列記法のオーバーロード
<?php class F implements ArrayAccess { protected $_args = array(); public function offsetGet($name) { $this->_args[] = $name; return $this; } public function dump() { Zend_Debug::dump($this->_args); } public function offsetSet($offset, $value) {} public function offsetExists($offset) {} public function offsetUnset($offset) {} }
このクラスは、配列記法でアクセスすると、内部配列にそれを追加します。したがって、このインスタンスには配列記法でいくつでも引数をセットできるようなクラスになります。
<?php $test = new F; $tmp = $test['test'][3]; //通常だと、配列にアクセスする記法ですが、ここでは$testオブジェクトに引数"test" 3を順に与えています。 //返り値は与えた引数を内部に持ったオブジェクトになります。 $tmp = $tmp['foo']; $tmp->dump();
たとえばFの派生クラスF0の実装として、引数を3つ与えられるとFX型のオブジェクトを返すものを作った時、
F1 = F0[$x];
とすることで、$xが既に与えられて、残り引数2つを与えるとFX型が得られるオブジェクトF1を返すことができるようになります。
つまり、
<?php //3引数 $instance0 = new F0(); $instanceX = $instance0->apply($x, $y, $z); $instance1 = $instance0[$x]; $instance2 = $instance1[$y]; $instance3 = $instance2[$z];
としたとき、
$instanceXと$instance3は同じ型になるような、配列記法を利用した関数オブジェクトを作成することができるようになります。
関数オブジェクト化
http://d.hatena.ne.jp/noopable/20090316/1237166080
こちらに書いたクラスは任意の名前付き引数でしたが、配列記法でやるときは純粋に関数型っぽいカリー化や高階化に向いていそうです。上のサンプル、getでsetするのはキモイですがフェイクです。offsetGetで新しい関数オブジェクトを返すのが本来の使い方になると思います。
両方できることがわかれば、引数の順序を重要視するか、それとも引数のインデックスを重要視するかは、実務上のニーズに合わせたいと思います。