Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
CakePHPの内部実装 から理解するPSR-7
Search
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.8k
大テーブルと小テーブルのJOINのコスト計算の話
boro1234
5
2.1k
やさしいActiveRecordのDB接続のしくみ
boro1234
14
9.2k
テーブル定義変更の ガイドラインを作った話
boro1234
2
2k
正規化理論ことはじめ -数学的背景から理解する正規化の初手-
boro1234
1
1.2k
RDBおける候補キーを求めるためのアルゴリズム
boro1234
0
1.3k
Other Decks in Programming
See All in Programming
Snowflakeで業務アプリを作ろう。 Snowflakeのアプリ機能解説&実践ガイド
ayumu_yamaguchi
1
280
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
480
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
360
iOSDC2026登壇資料.pdf
riofujimon
0
170
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
150
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
4
2.3k
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
290
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
600
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
120
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
170
MVNOの申込からeSIM開通までをiOSアプリでつなぐ- 本人確認・MNP・通信事業者基盤をまたぐ実装
satotakeshi
0
430
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
700
Featured
See All Featured
What's in a price? How to price your products and services
michaelherold
247
13k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Mind Mapping
helmedeiros
1
360
Producing Creativity
orderedlist
PRO
348
41k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
500
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.2k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
440
Building a Scalable Design System with Sketch
lauravandoore
464
34k
Code Review Best Practice
trishagee
74
20k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
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して)クラスを⽤意することを 「インターフェースを実装する」と⾔う • 同じインターフェースを実装している異なるクラスが作成でき、 それらが交換可能となる(なぜなら型が同じであるから) インターフェースとは