跳至正文
来自: 首页 » Coder Life » PHP: HyperText Preprocessor » nikic/fast-route中文文档

nikic/fast-route中文文档

之前在跟随@岁寒大佬的《利用 Composer 一步一步构建自己的 PHP 框架》 搭建了自己的  DoyleafPHP,路由使用的是GayHub上route关键词PHP语言下MostStars第一的nikic/fast-route,上一张现在的图

安装方式

通过composer安装:

composer require nikic/fast-route

需要PHP 5.4及更高版本.

使用方法

快速构造

<?php

// 引入composer自动加载文件
require '/path/to/vendor/autoload.php';

// 声明路由规则*
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    $r->addRoute('GET', '/users', 'get_all_users_handler');
    // {id} must be a number (\d+)
    $r->addRoute('GET', '/user/{id:\d+}', 'get_user_handler');
    // The /{title} suffix is optional
    $r->addRoute('GET', '/articles/{id:\d+}[/{title}]', 'get_article_handler');
});

// 获取http请求方式和资源URI
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];

// 将url中的get传参方式(?foo=bar)剥离并对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:
        // ... 404 Not Found
        break;

    // 请求的HTTP⽅法与配置的不符合
    case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
        $allowedMethods = $routeInfo[1];
        // ... 405 Method Not Allowed
        break;

    // 调用$handler和$vars*
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        // ... call $handler with $vars
        break;
}

定义路由

通过调用 FastRoute\simpleDispatcher() 函数来定义路由,参数为可调用的FastRoute\RouteCollector实例。

通过在收集器实例上调用addRoute()来添加路由:

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

$method参数是该条路由匹配的一个大写的HTTP方法字符串。可以使用数组指定多个有效方法:

// 分两条调用
$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/xyz
$r->addRoute('GET', '/user/{id:\d+}', 'handler');

// 允许匹配/user/foobar,不匹配/user/foo/bar
$r->addRoute('GET', '/user/{name}', 'handler');

// 允许匹配/user/foo/bar
$r->addRoute('GET', '/user/{name:.+}', 'handler');

路由占位符的自定义模式不能使用捕获组。例如 {lang:(en|de)} 就不是一个有效的占位符,因为() 是一个捕获组。 但是您可以使用 {lang:en|de} 或{lang:(?:en|de)}。

(这里的捕获组我理解的就是可选项,只能是这二者之一的意思)

此外,可以使用[…]来表示可选路由,因此 /foo[bar]既能匹配 /foo,也能匹配/foobar。 可选部件仅可以出现在末尾位置,而不能出现在路径中间。

// 使用可选语法的路由
$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只告诉你你的URI对应哪个处理程序,你如何解释它取决于你。

常用请求的快捷写法

对于 GET, POST, PUT, PATCH, DELETE 和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 = FastRoute\cachedDispatcher(function(FastRoute\RouteCollector $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进行调度

URI 通过已生成的 dispatcher 中的 dispatch() 方法来调用。这个方法可以用来接收 HTTP 参数和 URI。这个库不会绑定到 PHP Web SAPI 上,所以您可以自行获取这两部分信息(并适当地标准化)。

dispatch() 方法返回一个数组,这个数组的第一个元素包含一个状态码。这个状态码只能是 Dispatcher::NOT_FOUND, Dispatcher::METHOD_NOT_ALLOWEDDispatcher::FOUND。 对于 Method Not Allowed 状态,返回数组的第二个元素是一个列表,这个列表包含了本 URI 可用的 HTTP 请求方式。

像这样:

[FastRoute\Dispatcher::METHOD_NOT_ALLOWED, ['GET', 'POST']]

说明:HTTP规范要求405 Method Not Allowed 响应包含“Allow:”头,用以详细说明所请求资源的可用方法。 使用 FastRoute 的应用程序在返回 405 响应时,应使用数组的第二个元素添加此标头。

对于得到的这个状态码(即 405),第二个数组元素是与路由关联的句柄,第三个数组元素是一个键值对应的占位符的字典。

就像这样:

/* 路由拒绝了/user/nikic/42的GET请求 */

[FastRoute\Dispatcher::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);
}

路由解析器获取路由模式字符串并将其转换为路由信息数组,其中每个路线信息又是它的部分数组。

/* 本路由/user/{id:\d+}[/{name}]被转化为下述数组: */
[
    [
        '/user/',
        ['id', '\d+'],
    ],
    [
        '/user/',
        ['id', '\d+'],
        '/',
        ['name', '[^/]+'],
    ],
]

然后可以将该数组传递给数据生成器的 addRoute() 方法,在添加了所有路由之后,调用生成器的 getData(),它将返回调度器所需的所有路由数据。

调度程序通过构造函数接受路由数据,并提供 dispatch() 方法。

路由解析器可以被单独覆盖,然而数据生成器和调度器应该总是一起修改,因为前者的输出与后者的输入紧密耦合。

当使用 simpleDispatcher / cachedDispatcher 时,可以通过传入额外的参数,进行覆盖

<?php

$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    /* ... */
}, [
    'routeParser' => 'FastRoute\\RouteParser\\Std',
    'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased',
    'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased',
]);

上面给出了默认的设置,通过把 GroupCountBased 替换成 GroupPosBased 可以使用完全不同的调度策略

关于HEAD请求的说明

HTTP 规范要求服务器 同时支持 GET 和 HEAD 方法

GET和HEAD方法必须得到所有通用服务器的支持

为避免强制用户为每个资源手动注册 HEAD 路由,将使用一个匹配的 GET 路由响应请求。PHP web SAPI 透明地从 HEAD 响应中移除实体主体,所以这种行为对绝大多数用户没有影响。

但是,在 Web SAPI 环境外部使用 FastRoute ,绝不能发送响应 HEAD 请求而生成的实体主体,如果你是非 SAPI 用户,这是你的责任;在这种情况下,FastRoute 无权限制你破坏 HTTP 。

最后,请注意,应用程序可以始终为给定资源指定其自己的 HEAD 方法路由以完全绕过此行为。

推荐另一篇同期其他大佬翻译的文章

发表回复

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据