
PHPでjavaみたいにフィールドインジェクション
Posted: 2014-11-13 01:01 |
PHP全般
前書き
自分で使う為にコンソール用のパッケージを作りまして、
Laravel使う程でもないほんとに小さいwebアプリ用に折角だからマイクロフレームワークみたいなの作ろう!と思い立って
作っていたんです
コンソール様のやつで作った、
traitとリフレクションを使って簡単にioc!みたいな感じのものがあるんですがね、
どんなものかというと、
// database component
'db' => "\\Iono\\Console\\Application\\Component\\DataStorage\\Db",
// cache component
'cache' => "\\Iono\\Console\\Application\\Component\\Cache\\Factory",
// redis component
'redis' => "\\Iono\\Console\\Application\\Component\\DataStorage\\Redis",
設定ファイルにこんな感じで配列のキー名と、それに対応するクラス名を記載する訳です
各クラス等からそれらを使う場合は、
use Iono\Console\Application\Traits\Component;
class User
{
use Component;
public function getDbComponent()
{
// use db component
return $this->db->connection();
}
}
とリードオンリーのトレイトを使うと、設定に記述した配列キーをプロパティとしてアクセスすると、
対応したクラスが勝手に呼ばれるという仕組みを作った訳です。
使うのは至ってシンプルで、折角なのでこれを使ってweb用のを作ればいいんじゃないか!と
ところが
やっぱりもうちょっとああしたいこうしたい的な欲求が出て、
もう少し頑張ればjavaみたいにフィールドインジェクションができそうだと思いまして、
前にも途中まで作ってたんですが、またそれに対応したコンテナを作り始めました。
コンテナ!
まえにspring frameworkみたいな事をやろうとして途中で止めたんですが、
また始めました。
今はLaravelコンテナの
illuminate/containerを拡張しているところですが。
フィールドインジェクションを実装するにあたって、リフレクションを利用する訳ですが、
プロパティにsetValueしてもnewInstanceしたときにはそうならない訳ですよね
解決のヒントにspring frameworkの情報を集めたり(phperなので自分で実際に納得いく様に使えない・・・)しました
javaといえばAOPということで、
それらをPHPで実装している
Go! Aspect-Oriented Framework と、以前の職場がBEARだったので
BEAR.Sundayあたりをヒントに
とりあえず希望通りに動く様にベースを作ってみました。
AOPは作りませんがね!!!
色々やってみようと思う様になったのもLaravelがきっかけです。
批判、討論の標的にされる事が多いフレームワークですが、
自分にとってはPHPって楽しい、こんな事自分もやってみよう!って思えるものです
残念ながらそのコンテナは、いまのところそんなにパフォーマンスがよろしくないので、
リファクタリングと色々速度改善を頑張らないといけないですが、
チャレンジ感満載で楽しく考えながらやってるところです
コンテナはPimpleとかをベースに使うかもしれませんけども。
今現在実装されているものは
Spring Frameworkでおなじみの
@Component と
@Autowired です
まだScopeは実装されていないので、単純な利用しかできません
interfaceとclassをbindする訳ですが、
Spring Frameworkと同じ様に、とりあえずファイルをスキャンして
@Componentを探します
/**
* Interface RepositoryInterface
*/
interface AnnotationRepositoryInterface {}
/**
* @Component
* Class Repository
*/
class AnnotationRepository implements AnnotationRepositoryInterface {}
これで、コンテナにはinterfaceをキーに、実際にほしいインスタンスのクラスを登録します
実際は登録ではなく、Springと同じ様にbeanファイルみたいにシリアライズされたファイルを吐き出します
実際にインスタンスを作る場合に、そのファイルから関連性を取得してコンテナで解決する様にします
利用するときは、
class TestingClass
{
/**
* @Autowired("AnnotationRepositoryInterface")
*/
protected $class;
public function get()
{
return $this->class;
}
}
とするだけで、そのクラスのプロパティ$classは@Componentで指定されたものが入ってきます。
現在はこの関連付けの定義しかありません!
後から追加するものは、
@Component("name") です
これは、インターフェイスだけでなく、純粋にコンテナにその名前でクラスを登録して、
利用するときにその名前で利用する感じになります。
spring Frameworkがまだ全然分かっていないですが、たぶん
/**
* @Component("name")
*/
class Repository
{
}
となって、利用する場合は、
/**
* @Value("name")
*/
protected $property;
になると思います
@Resourceよりも単純にその名前だけを指定する感じでしょうか・・(自信ナイ)
@Scope ももちろん追加します
@Scope(“singleton”) でシングルトン、デフォルトは通常のクラス内で共有されるものになる予定です。
これらは、@Componentと一緒に使う感じになるでしょう!多分
/**
* @Component("name")
* @Scope("singleton")
*/
class Repository
{
}
まだ先ですが・・
これらの現在の実装は、実際に利用する場合に
$this->container->make("Hoge")
となりますが、実際にはHogeクラスを継承した別のクラスがコンパイルというか、
PHP-Parser を使って吐き出されて実行されるようになっています。
今はデモレベルでしか動かないので今後はパフォーマンスとソースコードを綺麗に、
実装方法ももう少しシンプルにを目標にいじっていく予定です。
scannerも波動拳が打てそうなネストなので直さなければ。。
そのコンテナライブラリ
これが出来たら好きなものを好きな様に組み合わせる事が何も意識せずに遊べるハズ・・!
以上、最近やっていることでした
PHPでやる意味あるの?と云われれば、
趣味です としか言えませんね!!