2014年11月13日木曜日

フレームワーク自作したい病が発生した

あまりに内容が薄いメモなので、自分のブログで書くことに。下書きみたいなものかと思われる。

StackPHPを参考にフレームワーク自作を始めた。自作すると大変、と言うのは経験済みだが、自作したくなってしまったのは仕方がない。

さて、大事な方向性は。

  1. StackPHPのように「ミドルウェアのスタック」でウェブアプリを構築する。ただし、StackPHPは使わずに自作することに(理由は後述)
  2. できるだけミドルウェア側に処理を寄せること。
  3. ミドルウェアはできるだけ疎結合であること。
  4. 既存のライブラリを有効に利用すること。
  5. ウェブサーバーのフロントに特化。DBなどのインフラ周りは含まない。
  6. ひとまずDIコンテナは利用しない。
書いてみたら真っ当な内容で、特に目新しさが感じられない。でも、調べたところではStackPHPを使ったフルフルなフレームワークが見つからなかった。

StackPHPを使わなかった理由

StackPHPのミドルウェアとして次の3つを満たす必要がある。
  1. SymfonyのHttpKernelInterfaceを実装すること。
  2. コンストラクターの第一引数として次のミドルウェアを受け取ること。
  3. (必要であれば)handleメソッドの中で、次のミドルウェアを呼び出して結果を返すこと。
疑問に感じたのは、ミドルウェアの中に、「実際の処理」と「次の処理を呼び出す」、という2つの責務を持っていること。多すぎるんじゃないか?!

例えば認証とかフィルターを考えてみる。
使い方としては、ミドルウェアとしてスタックの中に放り込んで、全アクセスで必ず認証をさせる。あるいは認証する条件(URLなど)をつける。そしてbeforeなど特別な場所から認証フィルターを掛けてみる。
などなど、いろんな使い方が想定できる。

つまり、次のミドルウェアを呼ばない使い方も多いようにみえる。そうなら、このミドルウェアは処理部分とスタックの部分を分離するほうがよくない?と思った。


で作ったのがStackableというクラス。これにHttpKernelInterfaceを実装した処理オブジェクトをpushしてあげると、次のスタックになる。スタックの考えが単純なので、コード自体は簡単だ。

DIコンテナは?

今後、PHPでもDIコンテナは重要な、いや使って当然な技術になってゆくと思う。が、今はいろんなコンテナが乱立しているし、標準もないし、使ってみると「遅いし」。

なので、ひとまずDIコンテナなしで作ってみることに。ただし依存性の注入は行うことにして、単純なfactory methodを使う方向で作ってます。

ミドルウェア作成してみた感想

実際にミドルウェアを作ってみると、意外と疎結合しないことがわかった。不便なままならいいけれど、やっぱり楽に開発したいと思うとマジックが必要になる。

例えばResponseを返すミドルウェアが複数存在する。一方、ここはフレームワークで統一したい(というか簡単にしたい)と思ったとする。結局、リスポンスオブジェクトを作るファクトリをアプリの中に持っておいて、必要に応じて取り出しては使う、みたいなコードがあちこちに散乱している。

データも共有することが多い。例えばリダイレクトしたら、ちょっとしたデータを一緒にセッションで送りたい。つまりリダイレクト部とセッションでデータを共有する必要がある。後CSRFトークンとかね。


こういう疎結合しながら共有するパターンといえばイベント(Event AggregatorやMediatorパターン)らしい。

しかしながらですよ、ミドルウェアは順番に実行するものですよね。勝手にpushするイベント系は、スタックとは相性が悪いのでは?。なので、「ひとまず」データやオブジェクトをアプリにpush/pullをするようにして、必要に応じて共有することにしてみた。もう少し他のFWの実装を調べてみる予定。


ライブラリについて

今、使っているライブラリ。意外と少なかった。
  • symfony/http-foundation
    スタックの基本なので、絶対外せない。
  • symfony/routing
    ルーティングに使う予定。もっと簡単なのを探してます。
  • league/flysystem
    設定ファイルを管理するためのファイルシステム。これにUnionManagerというのをかぶせることで、環境(productionやlocal)による設定を処理させる予定。
  • league/plates, aura/view
    生PHPベースのテンプレート。どちらを使うかは検討中。
  • wscore/form
    自作のHTMLフォーム生成コンポーネント。遅延評価でFluentにフォームが書けます。