PSR-7: HTTP Message Interfaces
PHP-FIGによって策定されたHTTPメッセージクラス(リクエスト・レスポンス)の仕様。 #PSR-HTTP
本文
PSR-7: HTTP message interfaces - PHP-FIG
PSR-7 Meta Document - PHP-FIG
インターフェイス psr/http-message - Packagist
定義されているinterfaceは以下の7種類。ネストされたものは継承関係にある。
Psr\Http\Message\MessageInterface
Psr\Http\Message\RequestInterface
Psr\Http\Message\ServerRequestInterface
Psr\Http\Message\ResponseInterface
Psr\Http\Message\StreamInterface
Psr\Http\Message\UriInterface
Psr\Http\Message\UploadedFileInterface
MessageInterfaceはHTTPリクエストとHTTPレスポンスの共通要素を抽象化したもので、ヘッダフィールドやボディなどリクエストとレスポンスの両方に存在するメソッドを持っている。この継承構造におけるひとつの発見は、「クライアントが送るリクエストオブジェクト(RequestInterface)よりもサーバが受け取って処理するリクエストオブジェクト(ServerRequestInterface)の方が情報量が多い」ということである。その理由はMeta Documentに「Rationale for ServerRequestInterface」として記載されている。
また、HTTPメッセージ本体以外の関連する要素としてStreamInterface、UriInterface、UploadedFileInterfaceという値オブジェクトのインターフェイスが定義されている。重要なのはHTTPメッセージのボディを表現するために、PHPのストリームでラップすることを想定したStreamInterfaceを提供していることだろう。
ユーティリティ fig/http-message-util - Packagist
fig/http-message-utilではHTTPメソッドの定数を持つFig\Http\Message\RequestMethodInterfaceと、ステータスコードの定数を持つFig\Http\Message\StatusCodeInterfaceという二つのインターフェイスを提供している。
このインターフェイスに依存することは必須ではないが、これらの定数をうまく利用することで、コード中の'GET'や200のようなマジックナンバーを避けることができる。どちらもメソッドの宣言を持っているわけではないが、実装クラスのimplementsに追加することでself::STATUS_OKのようなショートコーディングできることを意図している。
もちろんクラス組み込まずとも、以下のように使うこともできる。
code:php
<?php
use Fig\Http\Message\StatusCodeInterface as StatusCode;
class ResponseFactory implements StatusCodeInterface
{
public function createResponse($code = StatusCode::STATUS_OK)
{
self::STATUS_OKがいいか、StatusCode::STATUS_OKと書くのがいいかというのは好みの問題に属するだろう。
ただ、StatusCodeInterface::STATUS_IM_A_TEAPOT = 418という定数も定義されているが、これはいささか問題がある。この定数はHTTP 418 missing · Issue #2 · php-fig/http-message-utilという提案によってマージされたものだが、そもそもこのステータスコードはHTTPではなくRFC 2324 - Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0)が典拠だ。PSR-7はHTTPのインターフェイスであり、HTCPCP/1.0をカバーする目的のものではないし、正常なHTTP鯖が送出すべきものでもない。この議論についてはHTTPで「418 I’m a tea pot」を実装してはいけない(2018/10/18追記) - Qiitaに詳しい。現在策定作業中のRFC(インターネットドラフト)の HTTP Semanticsでは418はUnusedとして予約されており、将来的に4xx番台の番号が枯渇した際に再利用される可能性があることが示唆されているため、このインターネットドラフトが正式に発行された時には削除される可能性もあると見るべきだろう。
実装 psr/http-message-implementation
PSR-7はインターフェイスの定義なので、実装クラスがなければ利用できない。自作しても良いが、既存のものをどれか選ぶのが良いだろう。単体ライブラリとして導入するならPSR-17: HTTP Factoriesとセットになっているものから選択するのが良い。
Nyholm/psr7: A super lightweight PSR-7 implementation
2020年現在で最速を名乗るPSR-7/PSR-17実装クラス
laminas/laminas-diactoros: PSR HTTP Message implementations
PSR-17も実装されている
CakePHP(4.0.3)はこれを使っている
以前はZend Diactorosという名前だった
guzzle/psr7: PSR-7 HTTP message library
HTTPクライアントライブラリのGuzzleを入れるとついてくるPSR-7実装クラス
PSR-17も実装されている
Packagistのパッケージ名はguzzlehttp/psr7なので注意
ringcentral/psr7: PSR-7 HTTP message library
古いバージョンのguzzlehttp/psr7のフォーク版
PHP 5.3のサポートを継続している
“currently mising ServerRequestInterface and UploadedFileInterface” と宣言されており、PSR-15と併せて使えない
出力(emit)
PSR-7オブジェクトをPHPのレスポンスとして実際に出力することをemitと言う。簡単なのでライブラリを使わずに自作しても良いのだけれど、特に理由がなければ利用すべきだろう。
laminas/laminas-httphandlerrunner: Execute PSR-15 RequestHandlerInterface instances and emit responses they generate.
元zendframework/zend-httphandlerrunner
ど定番の鉄板
nyholm/psr7もguzzle/psr7もドキュメントでこれを紹介してるし、CakePHPも依存してる
http-interop/response-sender: PSR-7 Response sender function
シンプルな関数だけが欲しい場合はこっちでもいい
が、あまり使われてないのでlaminas-httphandlerrunnerの方がいいと思う
基本はこれだけ
code:php
<?php
$psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory();
$responseBody = $psr17Factory->createStream('Hello world');
$response = $psr17Factory->createResponse(200)->withBody($responseBody);
(new \Laminas\HttpHandlerRunner\Emitter\SapiEmitter())->emit($response);