JavaScriptのfunctionにインスパイアされたようなようなものになった。
AnonymousClass \ パッケージ \ Openpear
http://openpear.org/package/AnonymousClass
AnonymousClassの特徴・制限
・メソッドは全てClosure Objectで、インスタンス変数として格納する。
・メソッドを定義する時は、第1引数はAnonymousClassインスタンス自身を受け取る必要がある。
・定義出来るものは全てpublic。
・staticに出来ない。(prototypeでstaticっぽく振る舞う事は出来る)
・prototypeで継承が出来る。
・プロトタイプチェーンも出来る。
・変数もメソッドもオーバーライドし放題。
主なメソッド
AnonymousClass::create(Closure $construct=null, AnonymousClass $prototype=null)
無名クラスを定義する。
第1引数は、定義する無名クラスのコンストラクタ。
第2引数は、プロトタイプ。
サンプル
いろんな書き方が出来るから、いろんな書き方をした。
<?php require_once 'AnonymousClass.php'; // Animal $animal = AnonymousClass::create(function($self) { $self->cry_count = 0; $self->cry = function($self) { echo "unknown...\n"; }; }); $animal->hello = function($self) { echo "Hello ".$self->name."!\n"; $self->cry(); }; // Dog $dog = AnonymousClass::create(function($self, $name) { $self->name = $name; $self->cry = function($self) { echo "wan!\n"; $self->cry_count++; }; }); $dog->prototype = $animal(); $pochi = $dog('pochi'); $pochi->hello(); // Cat $cat = $animal(); $cat->cry = function($self) { echo "nyaa!\n"; $self->cry_count++; }; $tama = $cat(); $tama->name = "tama"; $tama->hello();
実行結果
Hello pochi wan! Hello tama nyaa!
JavaScriptで書くと
こんな感じ。
// Animal var animal = function() { this.cry_count = 0; this.cry = function() { console.log("unknown..."); }; }; animal.prototype.hello = function() { console.log("Hello "+this.name); this.cry(); }; // Dog var dog = function(name) { this.name = name; this.cry = function() { console.log("wan!"); this.cry_count++; }; }; dog.prototype = new animal(); var pochi = new dog("pochi"); pochi.hello(); // Cat var cat = new animal(); cat.cry = function() { console.log("nyaa!"); this.cry_count++; }; var tama = (function() {var F=function(){}; F.prototype=cat; return new F();})(); tama.name = "tama"; tama.hello();
インストール
Pear
# pear channel-discover openpear.org # pear install openpear/AnonymousClass
Github
# git clone git://github.com/eth0jp/php-AnonymousClass.git
ボツ案 その1
stdClassを使う。
インスタンス変数のClosure Objectを直接実行しようとしても、stdClassに定義されたメソッドを実行しようとしてしまって見つからない。
だから->__invoke()をつける。
冗長。
<?php $mumei_class = function(){ $self = new stdClass(); $self->_total = 0; $self->add = function($x) use($self) { $self->_total += $x; }; $self->total = function() use($self) { return $self->_total; }; return $self; }; $a = $mumei_class(); $a->add->__invoke(10); $a->add->__invoke(10); $a->add->__invoke(10); echo $a->total->__invoke()."\n";
ボツ案 その2
配列を使う。
直接実行出来るけど、配列丸出しで格好悪い。
ちゃちゃっと何かやりたい時にはこれでもいい気がしなくもない。
<?php $mumei_class = function() { $self = array(); $self['_total'] = 0; $self['add'] = function($x) use(&$self) { $self['_total'] += $x; }; $self['total'] = function() use(&$self) { return $self['_total']; }; return $self; }; $a = $mumei_class(); $a['add'](10); $a['add'](10); echo $a['total']()."\n";