PHPでプロトタイプベース(っぽい)オブジェクト指向
PHPでプロトタイプベースのオブジェクト指向をやってみる - #詰んでる日記を見て、PHPでのプロトタイプベースオブジェクト指向について考える。
PHP5.3から、無名関数が使えるので、直感的に書くとこんな感じで、エラーになります。
<?php $obj = new stdClass(); $obj->hoge = function(){ echo "hogehoge"; }; $obj->hoge();
$ ./php-5.3.0/sapi/cli/php test1.php
Fatal error: Call to undefined method stdClass::hoge() in /home/yokkuns/work/php/php5_3/test1.php on line 6
これは、PHPのクラスは、プロパティとメソッドを別のハッシュテーブルで管理してるので、$obj->hoge() のように呼ばれると、メソッド用のハッシュテーブルを検索してしまうためです。
そこで、メソッドとしても呼べるように、__callメソッドを使って実装してみます。
<?php class Prototype { public function __call($method, $args){ if(property_exists($this, $method)){ return call_user_func_array($this->$method, $args); } return false; } } $obj = new Prototype(); $obj->hoge = function(){ echo "hogehoge\n"; }; $obj->hoge();
これで、期待通り、メソッドっぽく動かす事が出来ました!
しかし、まだ、問題があって、この無名関数を使った方法では、$thisを使うことが出来ません。
<?php $obj = new Prototype(); $obj->foo = 'foo'; $obj->hoge = function(){ echo $this->foo . "\n"; }; $obj->hoge();
$ ./php-5.3.0/sapi/cli/php test3.php
Fatal error: Using $this when not in object context in /home/yokkuns/work/php/php5_3/test3.php on line 15
$thisは、内部で各メソッドが第一引数として受け取ってるものなので、当然ですね。
なので、もし使いたいのであれば、第一引数(じゃなくてもいいけど)にオブジェクト自身を渡す関数を作成することになります。(サンプルで$SELFとなってるのは、$thisが予約語で使えないから)
<?php $obj = new Prototype(); $obj->foo = 'foo' $obj->hoge = function($SELF){ echo $SELF->foo . "\n"; $SELF->foo = 'hogehoge'; }; $obj->hoge($obj); echo $obj->foo . "\n";
おぉ、これでやっと、PHPでプロトタイプベース(っぽい)オブジェクト指向が出来そうですね!
※追記(2009/08/13)
以下のように、無名関数のuseキーワードを使用すれば、第一引数にオブジェクト自身を渡す必要が無いです。
<?php $obj = new Prototype(); $obj->foo = 'foo'; $obj->hoge = function() use ($obj) { echo $obj->foo . "\n"; $obj->foo = 'hogehoge'; }; $obj->hoge(); echo $obj->foo . "\n";
無名関数については、他の言語の先入観で、PHPのマニュアル全然見てませんでした。。。orz
id:t_komuraさん、ご指摘ありがとうございます!