簡易ルーター
テクノロジ系 / web (HTTP / $_GET / $_POST / form / php -S)
簡易ルーター
Lesson 12 / Chapter 6
1 つの PHP で複数 URL を捌く
php -S localhost:8000 index.php
- 第 2 引数を付けて起動すると、全リクエストが
index.phpに集まる /usersでも/postsでも/admin/loginでも、全部index.phpが呼ばれるindex.phpの中で 「来た URI が何か」を見て分岐 する
→ これが フロントコントローラ・パターン の最小形。Laravel など本格的なフレームワークもこの構造の上に乗っている。
分岐に必要なのは 2 つ
<?php $method = $_SERVER['REQUEST_METHOD']; // "GET" / "POST" / ... $uri = $_SERVER['REQUEST_URI']; // "/users" / "/posts?page=2"
| 何を見るか | 例 |
|---|---|
REQUEST_METHOD | GET / POST を区別 |
REQUEST_URI | / / /users / /posts を区別 |
この 2 つの組み合わせで応答を決める。
URI に query string が含まれることに注意
URL: http://localhost:8000/users?page=2 ↓ $_SERVER['REQUEST_URI'] = "/users?page=2" ← クエリも含む!
純粋なパスだけ欲しいときは parse_url を使う:
$path = parse_url($uri, PHP_URL_PATH); // "/users"
ドリルでは ? を含まない URI を渡すので parse_url 必須ではないが、本物のアプリでは 必ず これをやる。
URI だけで分岐するミニ例
<?php
$uri = $_SERVER['REQUEST_URI'];
if ($uri === '/users') {
echo "users一覧\n";
} elseif ($uri === '/posts') {
echo "posts一覧\n";
} else {
echo "404\n";
}if / elseif / elseのチェーンが最も読みやすい (3〜4 ルートまでなら)match式を使うとさらに短くなる
echo match ($uri) {
'/users' => "users一覧\n",
'/posts' => "posts一覧\n",
default => "404\n",
};method + URI の組で分岐
REST の原則: 同じ URI でも メソッドが違えば別の操作。
<?php
$method = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
$key = "{$method} {$uri}"; // "GET /users" のような文字列にまとめる
echo match ($key) {
'GET /users' => "一覧表示\n",
'POST /users' => "新規登録\n",
default => "404\n",
};"GET /users"のような文字列にして 1 つのmatchで捌くテクニック- フレームワークも内部では似たような table lookup をやっている
ルーティングが大きくなったら配列にする
$routes = [
'GET /' => 'home',
'GET /users' => 'users一覧',
'POST /users' => '新規登録',
'GET /posts' => 'posts一覧',
];
$key = "{$method} {$uri}";
echo ($routes[$key] ?? '404') . "\n";- if/elseif が増えてきたら 配列 (ルーティングテーブル) に逃がす
- これだけで「最小 Web フレームワーク」の心臓部に近づく
このチャプターでできるようになること
✅ REQUEST_METHOD + REQUEST_URI で分岐できる
✅ 1 つの PHP で複数 URL を捌ける
✅ ルートを配列に持つと拡張しやすいと知っている
✅ フレームワークが内部でやっていることを大まかにイメージできる
→ ドリルへ。本コース最終チャプター。
考えてみよう
既定では正解・不正解の判定はしません。自分のペースで「答えを見る」を。採点してほしい場合だけ「採点してほしい」を押してください。
ドリル 01 — GET / のみ受け付けるミニルーター
問題
$_SERVER['REQUEST_METHOD'] と $_SERVER['REQUEST_URI'] を見て、次の通り応答する PHP を書いてください。
- method が
GETかつ URI が/のとき →"home"を 1 行出力 - それ以外 →
"404"を 1 行出力
採点ランナーは CLI 直実行なので、冒頭で stdin の 1 行目を method、2 行目を URI として $_SERVER に代入してください。
このドリルの入力例:
GET /
期待される出力:
home
採点
php scripts/grade.php topics/web/ch06-routing-basic/drill/01-method-router/
ヒント
$_SERVER['REQUEST_METHOD'] = trim(fgets(STDIN) ?: '');
$_SERVER['REQUEST_URI'] = trim(fgets(STDIN) ?: '');
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/') {
echo "home\n";
} else {
echo "404\n";
}ドリル 02 — URI で分岐するルーター
問題
$_SERVER['REQUEST_URI'] を見て、次の通り応答する PHP を書いてください。
/users→"users一覧"を 1 行出力/posts→"posts一覧"を 1 行出力- それ以外 →
"404"を 1 行出力
採点ランナーは CLI 直実行なので、冒頭で stdin の 1 行 を $_SERVER['REQUEST_URI'] に代入してください。
このドリルの入力例:
/users
期待される出力:
users一覧
採点
php scripts/grade.php topics/web/ch06-routing-basic/drill/02-uri-router/
ヒント
$_SERVER['REQUEST_URI'] = trim(fgets(STDIN) ?: '');
echo match ($_SERVER['REQUEST_URI']) {
'/users' => "users一覧\n",
'/posts' => "posts一覧\n",
default => "404\n",
};ドリル 03 — method + URI の組で分岐 (REST 風)
問題
$_SERVER['REQUEST_METHOD'] と $_SERVER['REQUEST_URI'] の組み合わせで、次の通り応答する PHP を書いてください。
GET /users→"一覧表示"を 1 行出力POST /users→"新規登録"を 1 行出力- それ以外 →
"404"を 1 行出力
採点ランナーは CLI 直実行なので、冒頭で stdin の 1 行目を method、2 行目を URI として $_SERVER に代入してください。
このドリルの入力例:
POST /users
期待される出力:
新規登録
採点
php scripts/grade.php topics/web/ch06-routing-basic/drill/03-method-uri/
ヒント
$_SERVER['REQUEST_METHOD'] = trim(fgets(STDIN) ?: '');
$_SERVER['REQUEST_URI'] = trim(fgets(STDIN) ?: '');
$key = $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'];
echo match ($key) {
'GET /users' => "一覧表示\n",
'POST /users' => "新規登録\n",
default => "404\n",
};「METHOD URI という文字列にまとめて 1 つの match で捌く」が小ぶりなアプリのお決まりパターン。