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
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.9k
大テーブルと小テーブルのJOINのコスト計算の話
boro1234
5
2.1k
やさしいActiveRecordのDB接続のしくみ
boro1234
14
9.2k
テーブル定義変更の ガイドラインを作った話
boro1234
2
2.1k
正規化理論ことはじめ -数学的背景から理解する正規化の初手-
boro1234
1
1.2k
RDBおける候補キーを求めるためのアルゴリズム
boro1234
0
1.3k
Other Decks in Programming
See All in Programming
FreeBSDでZabbixを動かす
kenkino
0
350
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
1
2.1k
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.7k
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
180
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
140
AI時代のコードレビューは人に向けるな、仕組みに向けろ
texmeijin
5
3.3k
モデルのリファクタリングが難しいと思ったら、そもそも複雑だったのはビジネス仕様だった ? / is-the-business-domain-the-real-complexity
hatsu38
0
430
GitHubハンズオン講座 — 実務レベルのチーム開発のフローを身につけよう
junhat6
0
110
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
660
App Intentsのビルドプロセスを支える技術
kntkymt
0
490
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
520
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
470
Featured
See All Featured
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
290
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.7k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
290
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
18k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Utilizing Notion as your number one productivity tool
mfonobong
4
610
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
380
GraphQLとの向き合い方2022年版
quramy
50
15k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
390
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
750
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
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して)クラスを⽤意することを 「インターフェースを実装する」と⾔う • 同じインターフェースを実装している異なるクラスが作成でき、 それらが交換可能となる(なぜなら型が同じであるから) インターフェースとは