1. asaokamei

    No comment

    asaokamei
Changes in body
Source | HTML | Preview
@@ -1,96 +1,98 @@
+> [追記:2018/03/04] ミドルウェアの仕様が「[PSR-15: HTTP Server Request Handlers](https://www.php-fig.org/psr/psr-15/)」として標準化されました。ここで説明した内容と大きく異るインターフェースが採用されてます。採用の経緯は[こちらのPSR-15ブログ(英語)](https://mwop.net/blog/2018-01-23-psr-15.html)が参考になります。
+
PSR-7のフレームワークとしては、[zend-expressive](https://github.com/zendframework/zend-expressive)、[SlimPHP/Slim 3](http://www.slimframework.com/)、そしてフレームワークではありませんが[Relay/Relay](http://relayphp.com/)などが出てきました。
嬉しいのは、ミドルウェアのAPIが全て同じことです。
```php
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next);
```
ひとつミドルウェアを作れば、上記3つのフレームワークのどれでも使いまわせることになります。
なんて素晴らしい!
でも、**なぜ、ミドルウェアはこの形なのでしょう?**
### Express.JS
この形は、node.js用のウェブアプリケーションフレームワークである[Express.js](http://expressjs.com/ja/)のミドルウェアと同じ、という説明があります。でも、答えになってない!
疑問が頭から離れず夜も寝られなくて。やっといくつか理由を考えついたので書いてみます。
ServerRequestInterface `$request`
---------------------------------
まずは最初の引数、`$request`から。
これがないと、なんの処理をしていいのか皆目わからない。ので、必須なのは自明、と言った感じでしょうか。
ちなみに。
Symfonyや、同じコンポーネントを使っているStackPHPでのミドルウェアは、`$request`だけにフラグが2つという構造になっています。([HttpKernelInterface](https://github.com/symfony/http-kernel/blob/3.0/HttpKernelInterface.php)参照)
> 例えばAPIを`$request`だけにしてしまえば、簡単で分かりやすいのに、なぜ3つも引数が増えてしまうのだろう?というのが疑問の始まり。
ResponseInterface `$response`
-----------------------------
次は`$response`。
ミドルウェアに、なぜレスポンスオブジェクトが必要なのか?
PSR-7や最初に説明したミドルウェアの大事な点として、**フレームワークに依存しないコードを書きたい**というのがあります。
例えば認証用ミドルウェアなどは、認証に失敗した場合にレスポンスを返す場合があります。**フレームワークに依存しないということは、オブジェクトを生成できない**、と同じことだと気が付きました。
実際にPSR-7には**オブジェクト生成に関するAPIはありません**。
なので、レスポンスオブジェクトを渡してもらう必要があるわけです。
callable `$next`
----------------
最後の`$next`というコーラブル変数。これは、こんな感じで使います。
```php
function __invoke($req, $res, $next) {
// ここで前処理をする!
if($next) {
$res = $next($req, $res); // next, please!
}
// ここで後処理もできる!
return $res;
}
```
この形の良い所は、**次のミドルウェアを呼ぶ前と後の両方で処理を書ける**ことです。
ところで`$next`がない場合は、どうやって後処理をするのでしょう?
Symfonyの場合は、[TerminableInterface](https://github.com/symfony/http-kernel/blob/3.0/TerminableInterface.php)というのを使います。ミドルウェアが`TerminableInterface`を実装している場合は、*アプリの実行が終了*したら、`terminate`メソッドが呼ばれることになってます。
> 多分。実は確認できないので、間違ってるかも。
突然、**面倒な感じになってきました**。
また前処理、後処理以外でも、場合によっては**次の処理を呼ばない**という実装も簡単に実装できます(コメント参照)。外側のフレームワークに依存することなく、とても柔軟性の高い処理を実装できるといえると思います。
最後に
====
今のAPIで最初に疑問に思ったのは、`$next`が入ることでした。本来の処理に必要な`$request`と`$response`以外に、次のミドルウェアを呼び出すという、別の責務がミドルウェアに発生するからです。
> このAPIでミドルウェア作ると、他の形に応用しずらい気がするんですよね。理由は`$next`が入り込んでくるから。
でも、この形が一番シンプルになる気がしてきました。やはり使われるコードというのは理由があるのですね。後から考えると当たり前な結論な気がしますが、考えている間は面白かったです。
> なお、この形が**本当に標準のようになるかは、まだ分かりません。**