707 文字
4 分
phpのroutingライブラリAltorouterの紹介
2021-07-23
タグなし

phpのroutingライブラリAltorouterの紹介#

モチベーション#

webアプリケーションのよくあるパターンは、index.phpで処理を受けたらURIに応じてルーティングしてリクエストされた処理を実行するというものですが、フレームワークを使っていないアプリケーションの場合、URIがそのまま、実行されるスクリプトのファイル名になっているケースがあります(hoge.com/login.phpみたいな感じ)。こういったアプリケーションの保守をしやすくするためにルーティングを入れたかったのでAltoRouterというライブラリを(超基本的な使い方だけですが)検証してみました。

Altorouterとは#

klein.phpに影響を受けたルーティングライブラリだそうです。

公式ドキュメント

類似ライブラリとの比較

サンプルリポジトリ#

https://github.com/isanasan/test_altorouter

導入#

composerで普通に入れる

composer require altorouter/altorouter

実装例#

単純な例で検証してみます。

Terminal window
.
├── 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/へアクセス image

http://127.0.0.1:3939/userへアクセス image

このようにアクセスした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>

参考#

https://www.youtube.com/watch?v=tbYa0rJQyoM