cklamm/router

PHP 路由器

1.0.1 2023-06-28 09:12 UTC

This package is auto-updated.

Last update: 2024-09-28 11:47:21 UTC


README

显然,PHP 的路由库数量不足,所以我写了这个。开个玩笑,我不建议使用这个库来代替像 FastRouteSymfony Routing 组件这样的流行库。我主要是作为练习写的。

话虽如此,这个库能做什么呢?像任何路由器一样,它允许你定义当请求特定 URL 时,你的 PHP 应用程序应该调用哪个功能。它还支持不同的 HTTP 方法、路由参数(包括可选和通配符参数)、路由分组、中间件和通过命名路由生成路径。

内容

安装

此库可以通过 Composer 安装。

composer require cklamm/router

使用示例

这是一个简化示例,展示了最重要的功能。解释可以在本文档的相关部分找到。

$router = new \cklamm\Router\Router();      // instantiation

$router->middleware('global');              // global middleware
$router->get('', 'handler', 'home');        // home route (with name)

$router->group('pages', function () {       // route group
    $this->get('', 'page.index');           // GET route for pages
    $this->get('create', 'page.create');    // GET route for pages/create
    $this->post('', 'page.store');          // POST route for pages
    $this->get(':id', 'page.show');         // GET route for pages/:id
    $this->get(':id/edit', 'page.edit');    // GET route for pages/:id/edit
    $this->put(':id', 'page.update');       // PUT route for pages/:id
    $this->delete(':id', 'page.delete');    // DELETE route for pages/:id
})->middleware('mw1', 'mw2');               // group middleware

$router->get('foo/?opt', 'optional');       // optional parameter
$router->get('bar/*any', 'wildcard');       // wildcard parameter

$router->dispatch('get', 'pages/5/edit');   // dispatch requested path

定义路由

可以使用 add 方法定义路由。

add(string $method, string $route, mixed $handler, string $name = null): Route

  • $method 是 HTTP 方法,将被转换为大写。
  • $route 是实际的路线定义,可以包含 参数
  • $handler 可以是一个字符串,也可以是一个回调函数,当请求此路由时应执行此回调函数。调用这样的函数由实现应用程序负责。
  • 可选的 $name 用于为这个路由 生成路径。路由名称必须是唯一的。

存在针对常见 HTTP 动作的快捷方法(GET, POST, PUT, PATCH, DELETE)。以下两个定义是等效的。

$router->add('GET', 'foo/bar', 'handler', 'name');
$router->get('foo/bar', 'handler', 'name');

路由参数

路由定义可以包含参数。定义的路线的优先级对应于下表的顺序。因此,与许多其他路由库不同,路线定义的顺序并不重要,因为没有歧义。

以下路由有一个必需参数和两个可选参数。它匹配路径,如 calendar/2020calendar/2020/12calendar/2020/12/31

$router->get('calendar/:year/?month/?day', 'calendar');

⚠️ 注意,此库不使用正则表达式进行参数,因此上述路由也会匹配 calendar/foo/bar。任何验证都必须由实现应用程序完成。

路由分组

可以使用 group 方法对路由进行分组。

group(string $prefix, \Closure $cb): Node

  • $prefix 是此组中所有路由将具有的前缀。前缀可以由多个段组成。
  • $cb 是包含分组路由定义的回调函数。在此函数内部,$this 指的是 Router 实例。

路由分组可以嵌套。

$router->group('pages', function () {
    $this->get('', 'page.index');
    $this->get('create', 'page.create');
    $this->post('', 'page.store');

    $this->group(':id', function () {
        $this->get('', 'page.show');
        $this->get('edit', 'page.edit');
        $this->put('', 'page.update');
        $this->delete('', 'page.delete');
    });
});

中间件

许多 PHP 框架使用 中间件,它提供了应该在请求之前或之后执行的功能。并非每个中间件都应该对每个请求执行。此库使全局、一组路由或单个路由分配中间件变得容易。

全局中间件

可以为每个路由直接分配应执行的中间件。

$router->middleware('global1');
$router->middleware('global2');

您不必反复调用方法,可以一次性传递多个中间件名称。

$router->middleware('global1', 'global2');

分组中间件

对于多个路由需要执行的中间件,可以分配给路由组。如果您不希望分组路由具有公共前缀,请使用空字符串作为前缀。

$router->group('foo', function () {
    $this->get('bar', 'handler');
})->middleware('mw1', 'mw2');

路由中间件

仅对单个路由需要执行的中间件可以分配给该路由。请注意,与全局和分组中间件不同,路由中间件仅适用于该路由的HTTP方法。

$router->get('foo/bar', 'handler')->middleware('mw1', 'mw2');

分发

dispatch方法确定先前定义的哪些路由与给定的路径匹配。通常,该方法在每个请求中只调用一次。

dispatch(string $method, string $path): Result

  • $method是请求的HTTP方法。
  • $path是请求的路径(不带域名)。
$result = $router->dispatch('GET', 'pages/5/edit');

dispatch方法返回一个cklamm\Router\Result的实例,该实例具有以下公共属性。

如果为路由定义的处理程序是回调函数,则可以像这样执行

$handler = $result->handler;
$handler(...$result->parameters);

路径生成

可以使用path方法为命名路由生成路径。这对于提供指向应用程序不同页面的链接非常有用。

path(string $route, mixed $data = []): string

  • $route是路由的名称。它需要之前定义过。
  • $data是一个包含路由参数值的数组或对象。

如果将数字数组传递给path方法,它将按提供的顺序填充参数值。如果传递对象或关联数组,该方法将根据路由参数的名称填充值。

$router->get('pages/:id/edit', 'handler', 'page.edit');
$router->get('calendar/:year/?month/?day', 'handler', 'calendar');
$router->get('foo/*any', 'handler', 'wildcard');

$router->path('page.edit', [5]);            // pages/5/edit
$router->path('page.edit', ['id' => 5]);    // pages/5/edit

$router->path('calendar', [2020]);          // calendar/2020
$router->path('calendar', [2020, 12]);      // calendar/2020/12
$router->path('calendar', [2020, 12, 31]);  // calendar/2020/12/31
$router->path('calendar', [                 // calendar/2020/12/31
    'year' => 2020,
    'month' => 12,
    'day' => 31,
]);

$router->path('wildcard', ['a', 'b', 'c']); // foo/a/b/c
$router->path('wildcard', [                 // foo/a/b/c
    'any' => ['a', 'b', 'c']
]);