iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 28
2
Modern Web

成為 Modern PHPer系列 第 28

Day 28:PSR-7 帶來的變革

前言

昨天的文章中,我們提到 roadrunner 可以跟 PSR-7 相容,至於什麼是 PSR-7 呢?

PSR-7 HTTP message interface,其中定義了一系列 HTTP 協定中可使用的 interface,目的是讓實現(implement)這些 interface 的 Class 都可以相互溝通。

PSR-7 概述

PSR-7 一共定義了 7 個 interfaces(下述一併表現其繼承關係):

  • MessageInterface
    • RequestInterface
      • ServerRequestInterface
    • ResponseInterface
  • StreamInterface
  • UriInterface
  • UploadedFileInterface

MessageInterface 系列

MessageInterface 分為兩大類:RequestInterfaceResponseInterface

RequestInterface

  • RequestInterface 表示 Client 發出的 HTTP Request
  • ServerRequestInterface 表示由 Server 端收到的 HTTP Request

RequestInterface 只需要在乎 Target、Method、Uri;ServerRequestInterface 還需要重新析構一些超全域變數($_GET, $_POST, $_SERVER, $_FILES 等)

ResponseInterface

表示由 Server 的 HTTP Response,其中比較重要的內容是 Status Code。

事實上,還可以獲取 Response Reason Phrase(例如 200 OKOK 就是 Reason Phrase),但它並不是必須元素,所以可能為空。

其它 interfaces

StreamInterface

用於描述 HTTP Stream 的介面,它是一個類似於 Day 19:自定義 Stream 中提到的 Stream Wrapper。

它用於讀取/寫入 HTTP Stream,例如用於讀取 Request,或為 Response 寫入一些額外資訊。

註:實現這個 interface 的 Class 是不能直接註冊為 Stream Wrapper 的(其實現的 methods 並不同)。

UriInterface

用於描述 Uri 的介面,主要是遵守 RFC 3986 的實現,讓設定/讀取 Uri 資訊時有個依據。

UploadeFileInterface

檔案上傳一直是很麻煩的議題,雖然 PHP 提供 $_FILES 這樣的超全域變數,但在某些情況下可能會失效

  • 當 HTTP Method 不是 POST 時
  • Unit Test
  • 非 SAPI 環境下執行 PHP 時,如 Swoole 或 Roadrunner

這個 Interface 的目的在於一致化各種不同的情況,並且能夠獲取上傳檔案中的相關資訊。

變革

PSR-7 最大的優勢在於:只要實現了 PSR-7 的 Interface,就可以無痛直接介接到其它也有實現 PSR-7 的程式之中。

PHP 與 Web Server 端

最明顯的例子應該就是 Roadrunner 了,只要實現了 PSR-7,Roadrunner 會處理掉其它所有的複雜事項。

當然 Swoole 也有 PSR-7 的 Bridge,例如 fastdlabs/http

Server 端

Slim Framework 中算是很早期就開始支援 PSR-7 的框架,下面展示一段程式

<?php

$app = Application::create();

$app->get('/home', function (Request $request, Response $response, array $args[]) {
    $response->getBody()->write('Hello World');
    
    return $response;
});

RequestResponse 中都是實現了 PSR-7 的介面,也就是說在這個 Closure 中可以直接使用 PSR-7 介面所提供的一些方法。

Client 端

Guzzle HTTP 應該是最早期支援 PSR-7 的 Client 端,這也讓它能夠輕易的 mock 一些 Request 及 Response,在 Unit Test 非常好用。

<?php

// 建立一些符合 PSR-7 的 MockHandler
$mock = new MockHandler([
    new Response(200, ['X-Foo' => 'Bar']),
    new Response(202, ['Content-Length' => 0]),
]);

// 為 Client 加入上面的 Mock Handler
$client = new Client(['handler' => HandlerStack::create($mock)]);

$client->request->get('GET', '/')->getStatusCode(); // 200
$client->request->get('GET', '/')->getStatusCode(); // 202

後記

PSR-7 統合了 PHP 對於 HTTP Message 的處理方式,這也間接產生了 PSR-15: Middleware。

還有兩篇鐵人賽,應該是還來得及講到 PSR-15 的基本應用才對。


上一篇
Day 27:另一個佈署時期的選擇 Roadrunner
下一篇
Day 29:PSR-15 帶來的新生態
系列文
成為 Modern PHPer30

尚未有邦友留言

立即登入留言