Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
CakePHPの内部実装 から理解するPSR-7
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
kubo ayumu
June 30, 2022
Programming
1.6k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
CakePHPの内部実装 から理解するPSR-7
https://lancersrecruit.connpass.com/event/248522/
kubo ayumu
June 30, 2022
More Decks by kubo ayumu
See All by kubo ayumu
MariaDB Connector/C のcaching_sha2_passwordプラグインの仕様について
boro1234
0
1.3k
caching_sha2_passwordのはなし
boro1234
0
2.7k
大テーブルと小テーブルのJOINのコスト計算の話
boro1234
5
2.1k
やさしいActiveRecordのDB接続のしくみ
boro1234
14
9.1k
テーブル定義変更の ガイドラインを作った話
boro1234
2
1.8k
正規化理論ことはじめ -数学的背景から理解する正規化の初手-
boro1234
1
1.2k
RDBおける候補キーを求めるためのアルゴリズム
boro1234
0
1.3k
Other Decks in Programming
See All in Programming
1B+ /day規模のログを管理する技術
broadleaf
0
130
AIキャラアプリkaiwaの低遅延音声通話基盤をどう作ったか - AWS Gravitonで支える低遅延・低コストAI Agent基盤
mogamit
0
170
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
150
Vite+ Unified Toolchain for the Web
naokihaba
0
740
Claude Opus 4.6以後の受託開発エンジニアの変化(Claude Code開発ノウハウ大公開スペシャルbyクラスメソッド)
iidatakuma
1
620
なぜ型を書くのか? TSKaigi2026で改めて考える #tskaigi_smarthr
kajitack
0
340
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
140
Creating Composable Callables in Contemporary C++
rollbear
0
200
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
2
260
AIエージェントで 変わるAndroid開発環境
takahirom
2
560
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
8.9k
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
240
Featured
See All Featured
Ethics towards AI in product and experience design
skipperchong
2
330
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
220
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
The Invisible Side of Design
smashingmag
301
52k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
450
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
690
Crafting Experiences
bethany
1
210
Site-Speed That Sticks
csswizardry
13
1.3k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.2k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
Transcript
$BLF1)1ͷ෦࣮ ͔Βཧղ͢Δ143
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 2
2 久保 路(くぼ あゆむ) ・LancersのQAチームに所属 ・CakePHP2→4へのバージョンアップ プロジェクトに参画中 ・クラフトビールが好き
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 3
3 public function add() { if ($this->request->is('post')) { $inputParams = $this->request->getData(); $user = $this->fetchTable('Users')->get($inputParams['id']); …… } }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 4
4 public function add() { if ($this->request->is('post')) { $inputParams = $this->request->getData(); $user = $this->fetchTable('Users')->get($inputParams['id']); …… } }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 5
5 public function add() { if ($this->request->is('post')) { $inputParams = $this->request->getData(); $user = $this->fetchTable('Users')->get($inputParams['id']); …… } } ServerRequestのインスタンスであり 仕様はPHPFIGという団体がPSRとして規定
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 6
今⽇はこの$this->requestを ちょっと深掘ってみます
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 7
7 今⽇持ち帰っていただきたいこと ・PSRとは⼀体何なのか ・PSR-7ではどんなインターフェースを定めているのか ・HTTPリクエストとレスポンスは フレームワーク内でどのように扱われているのか
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 8
8 1 PSRって? 2 PSR-7の主張 3 Cakeの内部実装を見てみる(Request編) 4 最後に アジェンダ
143ͬͯʁ
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 10
• PHP-FIGが定める規約 (PHPフレームワーク相互運⽤グループ) • ⽬的 ◦ 共通の仕様を定める ◦ 相互運⽤性を⾼める • 具体例 ◦ インターフェースの仕様 ◦ コーディング規約 ◦ etc… PSRとは
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 11
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 12
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 13
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 14
143ͷओு
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 16
• HTTPメッセージ(リクエスト・レスポンス)に関する インターフェースを定める • リクエストからレスポンスへを⽣成する処理の流れで はなく、それ⾃⾝の仕様を定める(流れはPSR15が定 めている) PSR-7とは
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 17
• インターフェース定義 PSR-7とは Psr¥Http¥MessageInterface Psr¥Http¥RequestInterface Psr¥Http¥ServerRequestInterface Psr¥Http¥ResponseInterface etc: StreamInterface, UriInterface, UploadInterface
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 18
PSR-7とは «interface» Message «interface» Request «interface» Response «interface» ServerRequest extends extends extends
$BLFͷ෦࣮ΛݟͯΈΔ 3FRVFTUฤ
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 20
«interface» Message «interface» Request «interface» Response «interface» ServerRequest extends extends extends
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 21
«interface» Message «interface» Request «interface» Response «interface» ServerRequest extends extends extends
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 22
• クライアントからサーバーへの要求とサーバーからクライアント への応答で構成され、それぞれに共通するメソッドを定義する • メソッド例 ◦ getProtocolVersion ◦ getHeader ◦ getBody ◦ etc.. • 継承インターフェース ◦ RequestInterface ◦ ResponseInterface MessageInterface
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 23
«interface» Message «interface» Request «interface» Response «interface» ServerRequest extends extends extends
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 24
• クライアントが送るリクエストの構成を定義する • リクエストターゲットを取得するためのメソッドやそれを⽤いて 新しいインスタンスを作成するためのメソッドが⽤意されている • メソッド例 ◦ getRequestTarget ◦ getMethod ◦ getUri • 継承インターフェース ◦ ServerRequestInterface RequestInterface
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 25
«interface» Message «interface» Request «interface» Response «interface» ServerRequest extends extends extends
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 26
• サーバーが受け取るリクエストの構成を定義する • RequestInterfaceの拡張であり、リクエストに関連するサーバ情 報が備わっている($_SERVERの内容など) • メソッド例 ◦ getServerParams ◦ getCookieParams ◦ getQueryParams • 実装先 ◦ cakephp/src/Http/ServerRequest.php ServerRequestInterface
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 27
cakephp/src/Http/ServerRequest.php CakePHPでの実例(ServerRequest実装先) /** * A class that helps wrap Request information and particulars about a single request. * Provides methods commonly used to introspect on the request headers and request body. */ class ServerRequest implements ServerRequestInterface { protected $params = [ 'plugin' => null, 'controller' => null, 'action' => null, '_ext' => null, 'pass' => [], ]; public function __construct(array $config = []) { $config += [ 'params' => $this->params, 'query' => [], 'post' => [], 'files' => [], 'cookies' => [], 'environment' => [], 'url' => '', 'uri' => null, 'base' => '', 'webroot' => '', 'input' => null, ]; $this->_setConfig($config); }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 28
cakephp/src/Http/ServerRequest.php CakePHPでの実例(ServerRequest実装先) /** * A class that helps wrap Request information and particulars about a single request. * Provides methods commonly used to introspect on the request headers and request body. */ class ServerRequest implements ServerRequestInterface { protected $params = [ 'plugin' => null, 'controller' => null, 'action' => null, '_ext' => null, 'pass' => [], ]; public function __construct(array $config = []) { $config += [ 'params' => $this->params, 'query' => [], 'post' => [], 'files' => [], 'cookies' => [], 'environment' => [], 'url' => '', 'uri' => null, 'base' => '', 'webroot' => '', 'input' => null, ]; $this->_setConfig($config); }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 29
どこでどのようにServerRequetの インスタンスが⽣成されている︖
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 30
cakephp/src/Http/Server.php CakePHPでの実例(ServerRequest⽣成の過 程) public function run(?ServerRequestInterface $request = null,?MiddlewareQueue $middlewareQueue = null): ResponseInterface { $this->bootstrap(); $request = $request ?: ServerRequestFactory::fromGlobals(); $middleware = $this->app->middleware($middleware Queue ?? new Middleware Queue()); if ($this->app instanceof PluginApplicationInterface) { $middleware = $this->app->plugin Middleware($middleware); } $this->dispatchEvent('Server.buildMiddleware', ['middleware' => $middleware]); $response = $this->runner->run($middleware, $request, $this->app); if ($request instanceof ServerRequest) { $request>getSession()->close(); } return $response; }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 31
cakephp/src/Http/Server.php CakePHPでの実例(ServerRequest⽣成の過 程) public function run(?ServerRequestInterface $request = null,?MiddlewareQueue $middlewareQueue = null): ResponseInterface { $this->bootstrap(); $request = $request ?: ServerRequestFactory::fromGlobals(); $middleware = $this->app->middleware($middleware Queue ?? new Middleware Queue()); if ($this->app instanceof PluginApplicationInterface) { $middleware = $this->app->plugin Middleware($middleware); } $this->dispatchEvent('Server.buildMiddleware', ['middleware' => $middleware]); $response = $this->runner->run($middleware, $request, $this->app); if ($request instanceof ServerRequest) { $request>getSession()->close(); } return $response; }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 32
cakephp/src/Http/ServerRequestFactory.php CakePHPでの実例(ServerRequest⽣成の過程) public static function fromGlobals( ?array $server = null, ?array $query = null, ?array $parsedBody = null, ?array $cookies = null, ?array $files = null ): ServerRequest { $server = normalizeServer($server ?: $_SERVER); $uri = static::createUri($server); /** @psalm-suppress NoInterfaceProperties */ $sessionConfig = (array)Configure::read('Session') + [ 'defaults' => 'php', 'cookiePath' => $uri->webroot, ]; $session = Session::create($sessionConfig); /** @psalm-suppress NoInterfaceProperties */ $request = new ServerRequest([ 'environment' => $server, 'uri' => $uri, 'cookies' => $cookie ?: $_COOKIE, 'query' => $query ?: $_GET, 'webroot' => $uri->webroot, 'base' => $uri->base, 'session' => $session, 'input' => $server['CAKEPHP_INPUT'] ?? null, ]); $request = static::marshalBodyAndRequestMethod($parsedBody ?? $_POST, $request); $request = static::marshalFiles($files ?? $_FILES, $request); return $request; }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 33
cakephp/src/Http/ServerRequestFactory.php CakePHPでの実例(ServerRequest⽣成の過程) public static function fromGlobals( ?array $server = null, ?array $query = null, ?array $parsedBody = null, ?array $cookies = null, ?array $files = null ): ServerRequest { $server = normalizeServer($server ?: $_SERVER); $uri = static::createUri($server); /** @psalm-suppress NoInterfaceProperties */ $sessionConfig = (array)Configure::read('Session') + [ 'defaults' => 'php', 'cookiePath' => $uri->webroot, ]; $session = Session::create($sessionConfig); /** @psalm-suppress NoInterfaceProperties */ $request = new ServerRequest([ 'environment' => $server, 'uri' => $uri, 'cookies' => $cookie ?: $_COOKIE, 'query' => $query ?: $_GET, 'webroot' => $uri->webroot, 'base' => $uri->base, 'session' => $session, 'input' => $server['CAKEPHP_INPUT'] ?? null, ]); $request = static::marshalBodyAndRequestMethod($parsedBody ?? $_POST, $request); $request = static::marshalFiles($files ?? $_FILES, $request); return $request; }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 34
cakephp/src/Http/ServerRequestFactory.php CakePHPでの実例(ServerRequest⽣成の過程) public static function fromGlobals( ?array $server = null, ?array $query = null, ?array $parsedBody = null, ?array $cookies = null, ?array $files = null ): ServerRequest { $server = normalizeServer($server ?: $_SERVER); $uri = static::createUri($server); /** @psalm-suppress NoInterfaceProperties */ $sessionConfig = (array)Configure::read('Session') + [ 'defaults' => 'php', 'cookiePath' => $uri->webroot, ]; $session = Session::create($sessionConfig); /** @psalm-suppress NoInterfaceProperties */ $request = new ServerRequest([ 'environment' => $server, 'uri' => $uri, 'cookies' => $cookie ?: $_COOKIE, 'query' => $query ?: $_GET, 'webroot' => $uri->webroot, 'base' => $uri->base, 'session' => $session, 'input' => $server['CAKEPHP_INPUT'] ?? null, ]); $request = static::marshalBodyAndRequestMethod($parsedBody ?? $_POST, $request); $request = static::marshalFiles($files ?? $_FILES, $request); return $request; }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 35
アプリケーションやミドルウェアを通して リクエストからレスポンスを⽣成する過程で、 リクエストやサーバー情報が詰まった スーパーグローバル変数からServerRequestオブ ジェクトを⽣成している CakePHPでの実例(ServerRequest⽣成の過 程)
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 36
どんな感じでServerRequetの インスタンスを使っている︖
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 37
cakephp/src/Controller/ControllerFactory.php CakePHPでの実例 public function getControllerClass(ServerRequest $request): ?string { $pluginPath = ''; $namespace = 'Controller'; $controller = $request->getParam('controller', ''); if ($request->getParam('plugin')) { $pluginPath = $request->getParam('plugin') . '.'; } if ($request->getParam('prefix')) { $prefix = $request->getParam('prefix'); …… /** @var class-string<¥Cake¥Controller¥Controller>|null */ return App::className($pluginPath . $controller, $namespace, 'Controller'); }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 38
cakephp/src/Controller/ControllerFactory.php CakePHPでの実例 public function getControllerClass(ServerRequest $request): ?string { $pluginPath = ''; $namespace = 'Controller'; $controller = $request->getParam('controller', ''); if ($request->getParam('plugin')) { $pluginPath = $request->getParam('plugin') . '.'; } if ($request->getParam('prefix')) { $prefix = $request->getParam('prefix'); …… /** @var class-string<¥Cake¥Controller¥Controller>|null */ return App::className($pluginPath . $controller, $namespace, 'Controller'); }
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 39
アプリケーション実⾏の際に様々なクラスで ServerRequestオブジェクトのプロパティか ら欲しい情報を取得している CakePHPでの実例
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 40
必要な時にグローバル変数から 直接読み込めばいいんじゃないの︖
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 41
スーパーグローバル変数の使⽤には デメリットがある
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 42
スーパーグローバル変数 ・変更可能なので別の場所で書き換えられる可能性がある ・テストがしづらい ServerRequestオブジェクト ・不変であるので安⼼ ・状態を付加する場合はwith~関数を使って新しくインスタ ンスを⽣成する ・テストの時もインスタンス作るだけでOK CakePHPでの実例
࠷ޙʹ
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 44
・PSRとは共通の仕様を定めるための規約であり、 PSR-7ではリクエストとレスポンスの仕様を定めている ・RequestInterfaceではクライアントの送るリクエストを定義し、 ServerRequestInterfaceはサーバーが受け取るリクエストを定義する ・フレームワーク内はServerRequestはグローバル変数をもとに⽣成され、 様々なクラスで適切にそのクラスのプロパティが読み込まれている ・内部実装追いかけるの楽しい まとめ
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 45
ありがとうございました︕
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 46
• HyperTextTransferProtcolの略 • TCPベースの通信プロトコル(それ⾃⾝はレイヤーで⾔うとアプ リケーション層のプロトコル) • HTTP リクエストとは、HTTPで指定されたフォーマットで記述 された(クライアント側からの)要求 • HTTP レスポンスとは、HTTPで指定されたフォーマットで記述 された(サーバー側からの)応答 • 上記をまとめてHTTPメッセージと⾔う HTTPとは
Confidential © 2018 for LANCERS, Inc. All Rights Reserved 47
• クラスが持つべきメソッドの名前や型の定義のみされている (すなわち構成が定義されている。以降その構成をまとめて 「型」と呼ぶ) • その型に従って(implementして)クラスを⽤意することを 「インターフェースを実装する」と⾔う • 同じインターフェースを実装している異なるクラスが作成でき、 それらが交換可能となる(なぜなら型が同じであるから) インターフェースとは