【PHP】FastRouteによるURLルーティング

URLルーティングにFastRouteを利用する

PHPのURLルーティング用ライブラリ、 FastRouteの利用方法を紹介します。

github
nikic/FastRoute

環境: PHP 8.1.15、 nikic/FastRoute 1.3.0

FastRouteの利用準備

composerを利用してプロジェクトにFastRouteのパッケージをインストールします。

composer require nikic/fast-route

FastRouteはフロントコントローラの仕組みを採用しているので .htaccessをドキュメントルート配下に作成します。

.htaccess

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]

フロントコントローラの概要については以下の記事を参照ください。

【PHP開発ガイド】フロントコントローラでリクエストを受け付ける

基本的なURLルーティング処理

FastRouteの利用準備が出来たら、URLルーティング処理をアプリケーションに実装します。

以下サンプルでは簡易な利用手順として、index.php内でFastRouteによるルーティング処理を直に行なっています。

(プロジェクト構成)

.
├── app
│   ├── composer.json
│   ├── composer.lock
│   └── vendor
└── htdocs
    ├── .htaccess
    └── index.php

index.php

<?php

require __DIR__ . '/../app/vendor/autoload.php';

$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    $r->addRoute('GET', '/', 'top');
    $r->addRoute('GET', '/login/', 'login');

    // {id} must be a number (\d+)
    $r->addRoute('GET', '/user/{id:\d+}', 'user');
});

// Fetch method and URI from somewhere
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];

// Strip query string (?foo=bar) and decode URI
if (false !== $pos = strpos($uri, '?')) {
    $uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);

$routeInfo = $dispatcher->dispatch($httpMethod, $uri);

switch ($routeInfo[0]) {
    case FastRoute\Dispatcher::NOT_FOUND:
        http_response_code(404);
        echo "404 Not Found";
        break;
    case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
        $allowedMethods = $routeInfo[1];
        http_response_code(405);
        echo "405 Method Not Allowed";
        break;
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];

        if (!empty($vars)) {
            // ... call $handler with $vars
            echo $handler($vars);
        } else {
            echo $handler();
        }

        break;
}

function top()
{
    return '<html><h1>top page</h1></html>';
}

function login()
{
    return '<html><h1>login page</h1></html>';
}

function user(array $args)
{
    $id = $args['id'];
    return "<html><h1>user id: $id</h1></html>";
}

こちらのサンプルは、ほとんど公式のgithub上の実装例のままですが、リクエストURLによって実行される関数を振り分ける処理を行なっています。

変数dispatcherを定義している箇所、simpleDispatcherの引数として実行される無名関数内にある、addRouteでリクエストメソッド(GETかPOST)、リクエストのパス、実行する関数を登録します。

それにより、リクエストパスが

/ のとき top
/login/のとき login
/user/{id} のとき user

とそれぞれ、定義された関数が実行されて必要なページを結果として返すようになっています。

ルーティング登録箇所は以下のように直接リクエストメソッドを指定して記述を簡略化することが出来ます。

$r->get('/', 'top');

また実装の中で、受け付けたリクエストが登録済みのルーティングに存在しない場合は404、定義されているリクエストメソッドと一致しない場合は405を、それぞれステータスコードとメッセージを返しています。

Follow me!