Slide 1

Slide 1 text

143ʹͷ͔ͬͬͯ όοΫΤϯυαʔόΛ ॻ͘ ゆゆ君(@Hyuyu_kun) in あくあたん工房 2024/01/24

Slide 2

Slide 2 text

PHP Standards Recommendations(PSR) 2

Slide 3

Slide 3 text

PHP Standards Recommendations(PSR) n いわゆるコーディング規約 n 公式ではなく、必ず守らなければいけない項目ではない n が、結構上手く出来ていそうな印象だったので、 今回は全力で乗っかっていく 3

Slide 4

Slide 4 text

背景 4

Slide 5

Slide 5 text

PHPのスーパーグローバル変数 5

Slide 6

Slide 6 text

スーパーグローバル変数 6 n PHPのどこからでもアクセスできる 変数 • $_SERVER, $_GET, $_POSTなど • e.g., http://localhost:8080/index?userId=123 n 連想配列なので… • アクセスする前にキーが存在するかどうかを チェックする必要がある • 再代入可 • 適当な運用をするとヤバい😇

Slide 7

Slide 7 text

そこで 7

Slide 8

Slide 8 text

PSR-7: HTTP message interfaces 8 n リクエスト、レスポンスなどからget したりsetしたりする インターフェースが定義されている • URL、ヘッダ、ボディなど

Slide 9

Slide 9 text

9 PSR-7: HTTP message interfaces interface MessageInterface { public function getHeaders(): array; public function withAddedHeader(string $name, $value): MessageInterface; public function getBody(): StreamInterface; public function withBody(StreamInterface $body): MessageInterface; //… } interface RequestInterface extends MessageInterface { public function getMethod(): string; public function getUri(): UriInterface; //… }

Slide 10

Slide 10 text

インターフェースだけ? 10

Slide 11

Slide 11 text

はい 11

Slide 12

Slide 12 text

HTTP message objectをどうやって作ればいいの? 12 具体的なRequestInterfaceを実装したクラスに依存すると意味ないので

Slide 13

Slide 13 text

PSR-17: HTTP Factories 13 n HTTP Message objectを作るための Factoryのインターフェース • Factoryがインスタンス化する • プログラマはnew Request()とか書かない代わりに Factoryを使う interface RequestFactoryInterface { public function createRequest( string $method, $uri ): RequestInterface; } interface ResponseFactoryInterface { public function createResponse( int $code = 200, string $reasonPhrase = ’’ ): ResponseInterface; }

Slide 14

Slide 14 text

(先にチラ見せ)インターフェースにしか依存していない 14

Slide 15

Slide 15 text

PSR-7, PSR-17の実装 15 n PSRの実装はあるのでそれを 利用する • ただし、どの実装を選んでも、インターフェース が共通なのでコードへの影響が無く差し替えが 可能なところが嬉しい! • https://github.com/Nyholm/psr7 (おすすめ) • https://github.com/guzzle/psr7 • https://github.com/laminas/laminas-http • https://github.com/slimphp/Slim-Psr7 https://github.com/Nyholm/psr7/blob/master/src/Factory/Psr17Factory.php

Slide 16

Slide 16 text

PSR-7のレスポンスが作れるようになった! 16

Slide 17

Slide 17 text

レスポンスをJSONとして返すには? 17

Slide 18

Slide 18 text

PHPのecho 18

Slide 19

Slide 19 text

HTMLをechoする 19 n HTMLを組み立ててechoすれば そのまま表示される Hello yuyukun!";

Slide 20

Slide 20 text

JSONをechoする 20 n JSONも同じ • ただしContent-Typeにapplication/jsonの指定 が必要 'success']);

Slide 21

Slide 21 text

Responseの中身をechoすればOK! 21

Slide 22

Slide 22 text

これもやっぱり実装があるので 22

Slide 23

Slide 23 text

23 PSR-7のResponseを受け取って echoする! ボディを取り出して https://github.com/laminas/laminas- httphandlerrunner/blob/2.11.x/src/Emitter/SapiStreamEmitter.php

Slide 24

Slide 24 text

レスポンスを作って返してみる 24

Slide 25

Slide 25 text

レスポンスを作って返してみる 25

Slide 26

Slide 26 text

26

Slide 27

Slide 27 text

今回つくるWebアプリケーション 27

Slide 28

Slide 28 text

28 今回のWebアプリケーション 今までの構成 最近主流になってきた構成

Slide 29

Slide 29 text

29 今回のWebアプリケーション 今までの構成 最近主流になってきた構成

Slide 30

Slide 30 text

30 今回のWebアプリケーション 今までの構成 最近主流になってきた構成 今回はここを作る

Slide 31

Slide 31 text

31 Webアプリケーションの処理のイメージ Request Middleware 1 例)リクエストの バリデーション Middleware N Router Controller 例)ユーザログイン /helloに対応する Controllerを呼び出す レスポンスを作る GET /hello Response HTTP Status: 200 Body: ‘{“status”: “success”}'

Slide 32

Slide 32 text

ControllerとMiddlewareのInterface 32

Slide 33

Slide 33 text

PSR-15 HTTP Server Request Handlers 33 n RequestHandlerInterface • PSR-7のRequestを受け取ってResponseを 返す n MiddlewareInterface • Requestを受け取って処理した後、 RequestHandlerに渡す • 結果としてResponseが返される interface RequestHandlerInterface { public function handle( ServerRequestInterface $request ): ResponseInterface; } interface MiddlewareInterface { public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface; }

Slide 34

Slide 34 text

Controllerを作る 34 // JSONを作ってResponseとして返す

Slide 35

Slide 35 text

35 Middlewareを作る このMiddlewareは何もせず受け取ったRequestをそのまま流す

Slide 36

Slide 36 text

36 Routerを作る関数(https://github.com/makise-co/http-router) RouterはRequestHandlerInterfaceを実装している →Requestを受け取って →適切なコントローラを呼び出してRequestを渡し →Responseを返す

Slide 37

Slide 37 text

37 今回のWebアプリケーション Request Middleware 1 リクエストの バリデーション Middleware N Router Controller ユーザログイン 対応するControllerを 呼び出す レスポンスを作る GET /hello Response HTTP Status: 200 Body: ‘{“status”: “success”}'

Slide 38

Slide 38 text

全部出来た 38

Slide 39

Slide 39 text

Middleware→Middleware→Router→Controllerをやる 39

Slide 40

Slide 40 text

40 今回のWebアプリケーション Request Middleware 1 リクエストの バリデーション Middleware N Router Controller ユーザログイン 対応するControllerを 呼び出す レスポンスを作る GET /hello Response HTTP Status: 200 Body: ‘{“status”: “success”}' Relay

Slide 41

Slide 41 text

41 Relayを使う(https://github.com/relayphp/Relay.Relay) RelayはRequestHandlerInterfaceを実装したクラス →handleメソッドはRequestを受け取ってResponseを返す

Slide 42

Slide 42 text

42 Relayの使い方 ↑RelayにRequestを渡してResponseが返ってくる ここ→

Slide 43

Slide 43 text

43 RelayはRunnerのhandleを呼び出す

Slide 44

Slide 44 text

Runnerはqueueから順に取り出しResponseを返す 44 ←$queue = [Middleware, Router]; ←$queue = [Router];

Slide 45

Slide 45 text

45 (再掲)Middlewareを作る このMiddlewareは何もせず受け取ったRequestをそのまま流す

Slide 46

Slide 46 text

Runnerはqueueから順に取り出しResponseを返す 46 ←最後に$this(Runner)のhandleを 呼び出すので、またここに帰ってくる ←RequestHandlerInterfaceのhandleは Responseを返すので、全体として RelayはResponseを返す ←$queue = [Middleware, Router]; ←$queue = [Router];

Slide 47

Slide 47 text

47 最後にResponseをEmitする

Slide 48

Slide 48 text

48 アクセスするとJSONが返ってくる

Slide 49

Slide 49 text

これでや〜〜〜っとJSONが出る 49

Slide 50

Slide 50 text

(再掲)JSONをechoする 50 n JSONも同じ • ただしContent-Typeにapplication/jsonの指定 が必要 'success']);

Slide 51

Slide 51 text

4行で書けた時とは大違い 51

Slide 52

Slide 52 text

PSRにのっかってバックエンドサーバを書く n バックエンドサーバとして必要な機能を実装してみた n PSRで定義されるインターフェースを使う • 疎結合な実装ができる • いろんなライブラリを組み合わせて活用できる n とはいえ、PSRを使っているものはまだまだ少ない印象 • お試しで作ってみて、その後放置されてるライブラリが多い? • 個人的にはとっても良さそうだったので、色々試行錯誤してみようと思う 52

Slide 53

Slide 53 text

おしまい 53

Slide 54

Slide 54 text

参考 n PSR-7とPSR-15によるWebアプリケーション実装パターン #phperkaigi • https://tadsan.fanbox.cc/posts/3674121 n PHP PSRによるいい感じにバックエンドサーバーを書く方法が知 りたい • https://zenn.dev/hiroya_w/scraps/eafb9bc5dbbddd n Hiroya-W/yuyu-articles-backend • https://github.com/Hiroya-W/yuyu-articles-backend 54