cklamm / router
PHP 路由器
Requires
- php: ^7.2 || ^8.0
Requires (Dev)
- phpunit/phpunit: ^8.5
This package is auto-updated.
Last update: 2024-09-28 11:47:21 UTC
README
显然,PHP 的路由库数量不足,所以我写了这个。开个玩笑,我不建议使用这个库来代替像 FastRoute 或 Symfony 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/2020
、calendar/2020/12
和 calendar/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'] ]);