こんにちは。
突然ですが、PHPのフレームワークを作ろうと思います。
大層なタイトルを掲げてしまいましたが、制作自体は全く5分ではありません。けっこう時間かかりました
じっくり時間を書けて調査した結果、記事に倣って書けば5分くらいで完成する、という意味での5分です
記事は2本立ての構成で、今回は技術選定・設計編です。
↑を作っていく過程を記事に残します。
数年前から動いているPHP-figという団体が提唱するPSRという仕様のうち、6(Caching Interface)、7(HTTP Message Interface)の登場に、衝撃が走りました
これはPHPのフレームワークもライブラリも変わるぞ 、と
特にPSR-7が強力で、 HTTPミドルウェア という概念が、フレームワーク依存のオレオレ仕様ではなくやっと標準的な形になったと言えます
PSR7の登場により、ほんの1~2年前くらいに誕生した比較的新しいフレームワークですら、 PSR-7に追従していなければもはやレガシー と言っても過言ではないと思います
そんな変化の激しい世界ですが、流行り廃りに依らない記事が書ければと思っております
この記事を書くに至ったきっかけのもう一つが、「PSR登場以後に流行ってるライブラリ」を全く追っていなかったので、
私自身の知見をアップデートするいい機会だなと思ったことが挙げられます
また、明示的に記事のコンテンツにはしませんが、裏目的として「フレームワークはただのPHPコードの塊だ」と感じてもらうことも狙っています
小さなパーツを組み上げていくことで、ブラックボックスなものではなく「ただのPHPじゃん」と身近に感じてもらいたいと思っています
なお、今回の記事ではOSSコミュニティやグロースなどはスコープ外とし、
単にPHPのコードやWAFといった仕様や技術的な箇所について書きます。
フレームワークの名前は Rush にしました
被ってなくて、言いやすくて、読みが明確で、短くて、覚えやすくて、さり気なく意味がこもっている名前です
Rush job(突貫工事、やっつけ仕事)から取っています
あまり良い意味の名前ではないですが、5分というテーマを掲げるならちょうど良い自嘲かなと思います
AdonisというNodejsのフレームワークと、
Slim v3にインスパイアされています
ちなみにAdonisはLaravelにインスパイアされています
PHPのサポート状況から対応すべきバージョンを決定しました
PHP 5.4のサポートってすでに終了していたんですね。 知りませんでした
thephpleague/routeではなくnikic/FastRouteを採用 thephpleague/routeのPSR-7対応版はまだrcなので、時期尚早だと判断した
zend-diactorosを採用
他にいい感じのライブラリがなかったのと、古に伝わりしZendブランドがPSRとか標準化に貢献していることに好感を感じるので採用しました
ブラウザにレスポンスを返す処理が見当たらなかったので、Slimのコードからそのまんまな処理をパクってきます。
oscarotero/psr7-middlewaresを採用
Slimと互換性があることと、色々種類が揃っているため便利そうなので採用しました
色々な種類のミドルウェアが入っているので、実装者が取捨選択する感じにしようと思います。
強いてあげるならGeneratorを使用して第三引数がなくなると、よりシンプルだなと思います
しかしPHPはほぼ全てが同期APIなので、Nodejs(Adonis)のような必然性、メリットが特にないため流行る将来が見えません。
ということでジェネレータ非対応ですがこのライブラリを採用します。
X-Forwarded-For
: the originating IP address of the client connecting to the Heroku routerX-Forwarded-Proto
: the originating protocol of the HTTP request (example: https)X-Forwarded-Port
: the originating port of the HTTP request (example: 443)X-Request-Start
: unix タイムスタンプ (milliseconds) when the request was received by the routerX-Request-Id
: the Heroku HTTP Request IDVia
: a code name for the Heroku routerLaravelのIlluminate\Eloquentを採用しました
もっともAPIが直感的だと思います。また、Laravelで使用されていることも有り、大規模な構成になっても耐えられそうなため採用しました
ちなみに内部ではDoctrineが使用されている箇所があります。
他に検討したライブラリだと、
fuel/ormやidiormやparis、doctrine/ormはAPIがイケてないと言った感じでした
phpdiを採用しました。
複雑なビジネスロジックを組んでいるとテストできないような膨大な化物ができあがってしまうことが良くあります
焼け石に水で、そもそも論はいくらでも言えますが、 明示的に意識させ、化物を産まれくくできる 点で、実装者のスキル差を軽減できるパターンの一つだと思います
モックをさらっと当ててテストが出来る点は一度覚えてしまうとやめられない快感です
そんな訳でDIコンテナの仕組みは入れておきたいです。でもSymfonyほど大袈裟なものは要らない
どれを採用するかとても迷いました。Githubでの人気具合だと
という感じでした
中くらいの人気度、コードベースでなく設定ベースなところからphpdiを採用します
蛇足。悩んだのでSlimを調べてみたところ、container-interop/container-interop
というライブラリが使われていました。幅広く抽象的なインタフェースだと思います。要メモ
自前で実装します。
といってもテンプレートエンジン自体を実装するのではなく、 複数のテンプレートエンジンを切り替えられる仕組み を作ります
ということで作りました
自前で作っても簡単ですが、自前ではなくhassankhan/configを採用しました
JSON, YAML, PHP, Iniに対応しているようです
こういった小さくて抽象的なライブラリ非常に好きです
PHP組み込み定数のDIRECTORY_SEPARATOR
は名前が長い。長過ぎます
とはいえFuelPHPのようにDS
といった略称を作っても仕方ないので、もっと根本的な解決策を探った結果、見つけました
さらに言えば、PHPのファイル操作関数は命名に統一性がなくバラバラで分かりにくいです
nodeでいうpathモジュールのようなのがほしいな~と探して見つけたのがこのライブラリです
なんだかんだでファイルパス操作はよく行うので、あらかじめ入れておくとコア層でもアプリ層でもいい感じになるだろう。と見込んで採用しました
アプリケーションのディレクトリ構成は以下のようにしようと思います。
.
├── bootstrap.php
├── config
│ ├── database.php
│ ├── middlewares.php
│ ├── providers.php
│ ├── routes.php
│ └── view.php
├── public
│ └── index.php
├── resouces
│ ├── storage
│ └── views
└── app
├── Http
│ ├── Controller
│ └── Middleware
└── Model
Adonisを真似ました。このディレクトリ構成気に入っています
コントローラは居るのか? という自問自答に対しては、「無名関数はユニットテストしにくい」という結果から採用しました
コントローラを使わなくても良いので、その辺のお手軽さも柔軟にやれればと思います。
いかがだったでしょうか。
これらのライブラリを組み合わせて、次回実装編でフレームワークを組み上げます。
この記事の中で、1つでも知らなくて役に立つライブラリが見つかっていれば、してやったりです。