PHP7 で PSR-7 と Middleware を使うマイクロフレームワークを書いてみた

コードはこちら。https://github.com/brtriver/karen

[追記]
この記事に書いてあるコードからさらに改良加えてApplicationレイヤーを作りました(v0.2)
詳しくはこっちの記事を参照をば
http://d.hatena.ne.jp/brtRiver/20160106/karen_framework

この記事の時点のコード(v0.1)を見たい場合は
https://github.com/brtriver/karen/tree/v0.1.3
からどうぞ。

なにこれ?

PSR-7が用意されてからコンポーネントを色々好きなのを選択できる時代が来つつあります。
たとえばzend-expressiveとか。

ただフレームワークががんばってこれらを抽象化しようとしてるのですが、もっとシンプルでもいいなぁと。

というわけで、コンポーネントをむき出しにして、ざぁーっと書いたらどうなるかをヤッてみたかったので書いただけという。

結果こんな感じに
https://github.com/brtriver/karen/blob/master/web/index.php

試してみたい人は

php -r "eval('?>'.file_get_contents('https://getcomposer.org/installer'));"
php composer.phar create-project brtriver/karen  ./<パス>
cd <パス>
make server
// http://localhost:8888/hello/karen_girls

で。

Karenでやったこと

PSR-7 とMiddleware は自由に差し替えられるように

逆にいうと、サービスコンテナ(DI)、ルーティングはフレームワークとして蜜になっててもいいかなと。

フレームワークのコントローラーは薄く

ルーティングのクロージャーで少し書きやすくするためのControllerクラスとTemplatableトレイトだけを用意。

「こういう処理をやる」ということをラベル(コメント)ブロック付けた

スコープが閉じられるわけじゃないです。あくまでもラベル。
ただインラインコメントを残すよりもわかりやすかなと。

<?php
container: {
    $c = new Container();
    ....
}

middleware: {
     $relayBuilder = new RelayBuilder();
      ...
}
さすがにサービスコンテナ無いと辛そう

コンテナは Container Interop というのも用意されてたりしますが、まだ公式というほどでもないのと、好きなの使えばいいじゃんということで使い慣れた Pimpleを選択。

別のコンテナ使ったとしても、Karen程度のフレームワークであればそんなに書き換えるのは大変じゃないと思う。

ルーティングは Aura.Router

ルーティングはクロージャーが定義できればいいので、使ったことがある Aura.Routerで

<?php
...
    $map->get('hello', '/hello/{name}', function($args, $controller) {
        $name = $args['name']?? 'karen';
        return $controller->render('Hello, ' . $name);
    })->tokens(['name' => '.*']);

PHP7だと issetじゃなくて "??" 使えるの便利ですね。
KarenではControllerクラスを用意して、便利関数やRequest, Responseオブジェクトにクロージャーからアクセス出来るようにしてあります。

コントローラークラスの拡張を無名クラスでもできるように

必要があればControllerをextendsした専用のコントローラーを用意すればいいのですが、PHP7で無名クラス使えるので無名クラスでControllerを拡張できるようにしてみました。

たとえば通常は

<?php
...
$c['controller'] = function($c) {
	return new Controller($c['request'], $['response']);
};

と、コントローラーの用意しますが、
Templatable トレイトを利用できるようにしたControllerを用意したい場合は

<?php
...
$c['controller'] = function($c) {
    $controller = new class($c['request'], $c['response']) extends Controller{
            use Templatable;
        };
    $controller->setTemplate($c['template']);

    return $controller;
};

Middleware は Realy で

詳しくはRealyを使ってみた。
これって知ってる人は知ってる Mojavi のアレですよね。(懐かしい

書いてみてどうだったの?

  • まだもう少しコードを整理して書くつもり。
  • コード書くのが疲れたので、感想はいつかのLTのネタとして。