PHP路由庫FastRoute的使用教學

2020-07-16 10:05:53

GitHub: https://github.com/nikic/FastRoute

這個庫提供了基於正規表示式的快速路由實現。這篇文章解釋了 FastRoute 是如何工作的和它為什麼很快。

安裝

通過 composer 安裝

composer require nikic/fast-route

要求 PHP 5.4 及更高的版本

使用

這是一個基本的使用範例

<?php
require '/path/to/vendor/autoload.php';
$dispatcher = FastRoutesimpleDispatcher(function(FastRouteRouteCollector $r) {
    $r->addRoute('GET', '/users', 'get_all_users_handler');
    // {id} 必須是一個數位 (d+)
    $r->addRoute('GET', '/user/{id:d+}', 'get_user_handler');
    //  /{title} 字尾是可選的
    $r->addRoute('GET', '/articles/{id:d+}[/{title}]', 'get_article_handler');
});
// 獲取請求的方法和 URI
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// 去除查詢字串( ? 後面的內容) 和 解碼 URI
if (false !== $pos = strpos($uri, '?')) {
    $uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
    case FastRouteDispatcher::NOT_FOUND:
        // ... 404 Not Found 沒找到對應的方法
        break;
    case FastRouteDispatcher::METHOD_NOT_ALLOWED:
        $allowedMethods = $routeInfo[1];
        // ... 405 Method Not Allowed  方法不允許
        break;
    case FastRouteDispatcher::FOUND: // 找到對應的方法
        $handler = $routeInfo[1]; // 獲得處理常式
        $vars = $routeInfo[2]; // 獲取請求引數
        // ... call $handler with $vars // 呼叫處理常式
        break;
}

定義路由

通過呼叫 FastRoutesimpleDispatcher() 函數來定義路由,該函數接受一個以 FastRouteRouteCollector 範例為引數的閉包作為引數。通過在 collector 範例裡面呼叫 addRoute() 增加路由。

$r->addRoute($method, $routePattern, $handler);

$method 是大寫的 HTTP 方法,能夠被某個路由匹配,可以使用陣列指定多個有效的 $method

// 這裡兩行呼叫
$r->addRoute('GET', '/test', 'handler');
$r->addRoute('POST', '/test', 'handler');
// 等同於這一行呼叫
$r->addRoute(['GET', 'POST'], '/test', 'handler');

預設情況下 $routePattern 使用一種語法,比如 {foo} 是指定名稱為 foo 的預留位置,可以匹配正規表示式 [^/]+. 。要調整預留位置匹配的模式,可以通過編寫 {bar:[0-9] +} 來指定自定義模式。一些例子

// 匹配 /user/42,不匹配 /user/xyx
$r->addRoute('GET', '/user/{id:d+}', 'handler');
// 匹配 /user/foobar,不匹配 /user/foo/bar
$r->addRoute('GET', '/user/{name}', 'handler');
// 匹配 /user/foobar,也匹配 /user/foo/bar
$r->addRoute('GET', '/user/{name:.+}', 'handler');

路由預留位置的自定義模式不能使用捕獲組,例如 {lang:(en|de)} 不是有效的預留位置,因為 () 是一個捕獲組,可以使用 {lang:en|de} 或者 {lang:(?:en|de)} 代替。

另外,在路由 [...] 中定義的部分是可選匹配的,所以 /foo[bar] 將匹配 /foo 和 /foobar 。路由可選部分只支援在定義的末尾,而不能在定義的中間。

// 這個路由有,[/{name}] 可選擇匹配部分
$r->addRoute('GET', '/user/{id:d+}[/{name}]', 'handler');
// 等同於這兩個路由
$r->addRoute('GET', '/user/{id:d+}', 'handler');
$r->addRoute('GET', '/user/{id:d+}/{name}', 'handler');
// 多層巢狀可選路由,也是支援的
$r->addRoute('GET', '/user[/{id:d+}[/{name}]]', 'handler');
// 這個路由定義無效,因為可選部分只能在定義的末尾
$r->addRoute('GET', '/user[/{id:d+}]/{name}', 'handler');

$handler 引數不一定必須是回撥函數,它也可以是控制器類名或任何其他型別的資料。FastRoute 只告訴你哪個 handler 對應 URI,如何解釋它取決於你。

請求方法的書寫快捷方式

對於 GETPOSTPUTPATCHDELETE HEAD 請求方法,可使用快捷方式。

$r->get('/get-route', 'get_handler');
$r->post('/post-route', 'post_handler');
// 等同於
$r->addRoute('GET', '/get-route', 'get_handler');
$r->addRoute('POST', '/post-route', 'post_handler');

路由組

你可以在一個組內定義路由,同一組內的路由有相同的字首。

$r->addGroup('/admin', function (RouteCollector $r) {
    $r->addRoute('GET', '/do-something', 'handler');
    $r->addRoute('GET', '/do-another-thing', 'handler');
    $r->addRoute('GET', '/do-something-else', 'handler');
});
// 等同於
$r->addRoute('GET', '/admin/do-something', 'handler');
$r->addRoute('GET', '/admin/do-another-thing', 'handler');
$r->addRoute('GET', '/admin/do-something-else', 'handler');

可以定義多層巢狀組結構。

快取

使用 simpleDispatcher 定義路由的回撥函數可以無縫快取。通過使用 cachedDispatcher 而不是 simpleDispatcher,可以快取生成的路由資料並從快取的資訊構建排程。

<?php
$dispatcher = FastRoutecachedDispatcher(function(FastRouteRouteCollector $r) {
    $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
    $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');
    $r->addRoute('GET', '/user/{name}', 'handler2');
}, [
    'cacheFile' => __DIR__ . '/route.cache', /* required 快取檔案路徑,必須設定 */
    'cacheDisabled' => IS_DEBUG_ENABLED,     /* optional, enabled by default 是否快取,可選引數,預設情況下開啟 */
]);

該函數的第二個引數是一個選項陣列,可用於指定快取檔案路徑等等。

排程 URI

通過呼叫 dispatch() 排程 URI。這個方法接受 HTTP 方法 和一個 URI 作為引數。獲得這兩個資訊是你自己的工作,這個庫並不系結到 PHP web SAPIs 。

dispatch() 返回一個陣列,第一個元素是一個狀態碼,狀態碼是 Dispatcher::NOT_FOUNDDispatcher::METHOD_NOT_ALLOWEDDispatcher::FOUND 其中之一。對於 Dispatcher::METHOD_NOT_ALLOWED 狀態,第二個陣列元素包含允許提供的 URI 的 HTTP 方法列表。

[FastRouteDispatcher::METHOD_NOT_ALLOWED, ['GET', 'POST']]

對於 Dispatcher::FOUND 狀態,第二個陣列元素是 $handler ,第三個陣列元素是是一個包含所有預留位置的陣列

/* Routing against GET /user/nikic/42 */
[FastRouteDispatcher::FOUND, 'handler0', ['name' => 'nikic', 'id' => '42']]

重寫路由解析器和排程器

這個庫使用三個元件,一個路由解析器,一個資料生成器,一個排程器。這個三個元件實現以下介面

<?php
namespace FastRoute;
interface RouteParser {
    public function parse($route);
}
interface DataGenerator {
    public function addRoute($httpMethod, $routeData, $handler);
    public function getData();
}
interface Dispatcher {
    const NOT_FOUND = 0, FOUND = 1, METHOD_NOT_ALLOWED = 2;
    public function dispatch($httpMethod, $uri);
}

路由解析器獲取路由模式字串並將其轉換為路由資訊陣列,其中每個路線資訊又是它的部分陣列。

/* The route /user/{id:d+}[/{name}] converts to the following array: */
[
    [
        '/user/',
        ['id', 'd+'],
    ],
    [
        '/user/',
        ['id', 'd+'],
        '/',
        ['name', '[^/]+'],
    ],
]

然後可以將該陣列傳遞給資料生成器的 addRoute() 方法,在新增了所有路由之後,呼叫生成器的 getData(),它將返回撥度器所需的所有路由資料。

排程程式通過建構函式接受路由資料,並提供 dispatch()方法。

路由解析器可以被單獨覆蓋,然而資料生成器和排程器應該總是一起修改,因為前者的輸出與後者的輸入緊密耦合。

當使用 simpleDispatcher / cachedDispatcher 時,可以通過傳入額外的引數,進行覆蓋

<?php
$dispatcher = FastRoutesimpleDispatcher(function(FastRouteRouteCollector $r) {
    /* ... */
}, [
    'routeParser' => 'FastRouteRouteParserStd',
    'dataGenerator' => 'FastRouteDataGeneratorGroupCountBased',
    'dispatcher' => 'FastRouteDispatcherGroupCountBased',
]);

上面給出了預設的設定,通過把 GroupCountBased 替換成 GroupPosBased 可以使用完全不同的排程策略

關於HEAD請求的說明

HTTP 規範要求伺服器 同時支援 GET HEAD 方法

GETHEAD方法必須得到所有通用伺服器的支援

為避免強制使用者為每個資源手動註冊 HEAD 路由,將使用一個匹配的 GET 路由響應請求。PHP web SAPI 透明地從 HEAD 響應中移除實體主體,所以這種行為對絕大多數使用者沒有影響。

但是,在 Web SAPI 環境外部使用 FastRoute ,絕不能傳送響應 HEAD 請求而生成的實體主體,如果你是非 SAPI 使用者,這是你的責任;在這種情況下,FastRoute 無許可權制你破壞 HTTP 。

最後,請注意,應用程式可以始終為給定資源指定其自己的 HEAD 方法路由以完全繞過此行為。

以上就是PHP路由庫FastRoute的使用教學的詳細內容,更多請關注TW511.COM其它相關文章!