phpのroutingライブラリAltorouterの紹介
モチベーション
webアプリケーションのよくあるパターンは、index.php
で処理を受けたらURIに応じてルーティングしてリクエストされた処理を実行するというものですが、フレームワークを使っていないアプリケーションの場合、URIがそのまま、実行されるスクリプトのファイル名になっているケースがあります(hoge.com/login.phpみたいな感じ)。こういったアプリケーションの保守をしやすくするためにルーティングを入れたかったのでAltoRouter
というライブラリを(超基本的な使い方だけですが)検証してみました。
Altorouterとは
klein.phpに影響を受けたルーティングライブラリだそうです。
サンプルリポジトリ
導入
composerで普通に入れる
composer require altorouter/altorouter
実装例
単純な例で検証してみます。
.├── composer.json├── composer.lock├── api│ └── user.php // 単純なスクリプトを置いてみる├── public│ └── index.php // ここにルーティング定義を書く└── src └── Http └── Handler └── Welcome.php //controllerぽい感じでクラスを置いてみる
index.php
の例
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
$router = new AltoRouter();
// スクリプトを直で呼び出す$router->map('GET|POST|PATCH|DELETE', '/user', function () { require_once __DIR__ . '/../api/user.php';});
// laravelっぽくクラスとメソッドを指定する$router->map('GET', '/', 'isanasan\Router\Http\Handler\Welcome::get', 'welcome');
$match = $router->match();
if ($match !== false) { if (is_callable($match['target'])) { $match['target'](); } else { $params = explode("::", $match['target']); $action = new $params[0](); call_user_func_array(array($action, $params[1]), $match['params']); }} else { header($_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found');}
src/Http/Handler
の中身
<?php
namespace isanasan\Router\Http\Handler;
class Welcome{ public function get() { echo 'welcome'; }}
api/user.php
の中身
<?php
switch ($_SERVER['REQUEST_METHOD']) { case 'GET': $response = 'isana'; echo $response; break; case 'POST': case 'PATCH': case 'DELETE':}
以下のコマンドでビルトインサーバを実行します。
php -S 127.0.0.1:3939 public/index.php -t public
http://127.0.0.1:3939/
へアクセス
http://127.0.0.1:3939/user
へアクセス
このようにアクセスしたURIに応じて処理をルーティングできました。今回は非常に簡単な例しか試していませんが、router->map()
の第二引数を/users/[i:id]/
のような形にすることでより実用的なルーティングが設定できます。
既存プロジェクトに入れて使う場合は、既に動いているページをrequire
で読み込むことで対応し、これから新しく追加していく機能はコントローラっぽい使い方でルーティングすると良いのではないでしょうか。
ハマりポイント
laravelっぽくルーティングする際にis_callable($match['target'])
で判定しようとしても$router->map()
の第三引数はただの文字列にしか過ぎないのでcall_user_func()
で呼べませんでした。
余談
検証はビルトインサーバーを使いましたがmod_phpなら.htaccess
を置きます。
.htaccess
の例
<IfModule mod_rewrite.c> # negotiation拡張を無効化 <IfModule mod_negotiation.c> Options -MultiViews -Indexes </IfModule> # phpファイルへの直接アクセスを禁じる <Files ~ "(\.php)$"> deny from all </Files> # index.phpへのアクセスを許可 <Files ~ "^(index\.php)"> allow from all </Files>
# public/index.phpへリライト RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteRule . public/index.php [L]</IfModule>