haszi/router

该包最新版本(1.0.0)没有可用的许可证信息。

路由器/调度器的学习练习

1.0.0 2023-11-27 14:07 UTC

This package is auto-updated.

Last update: 2024-09-27 16:03:12 UTC


README

编写用于了解路由器/调度器和编写这些内容的难点的路由器/调度器。

要求

PHP 8.0+

安装

composer require haszi/router

功能

支持

  • GET、HEAD、POST、PUT、DELETE、PATCH、OPTIONS HTTP请求方法
    • 每种方法的简写方法
  • 静态URI
  • 路由参数
  • 闭包和'controller@method'类型处理器
  • 路由分组
  • 为找不到的路由自定义处理器
  • 路由中间件之前

入门

基本用法

use Haszi\Router\Router;
use Haszi\Router\Dispatcher;

$router = new Router();
$router->addRoute('*', '/greet', function () { echo 'Hello World!'; });
$router->get('/users', 'Users@list');

$dispatcher = new Dispatcher($router);

$dispatcher->dispatch('GET', '/greet);

HTTP方法

该路由器支持以下HTTP方法

  • GET
  • HEAD
  • POST
  • PUT
  • DELETE
  • PATCH
  • OPTIONS

使用*代表HTTP方法将为上述每种HTTP方法添加一个路由。

对于上述每种方法,路由器中也有相应的简写方法。*的简写是方法'any'。

$router->get('/route', $handler);
$router->head('/route', $handler);
$router->post('/route', $handler);
$router->put('/route', $handler);
$router->delete('/route', $handler);
$router->patch('/route', $handler);
$router->options('/route', $handler);

$router->any('/route', $handler);

也可以使用HTTP方法字符串数组定义一个路径的多个HTTP方法。

$router->addRoute(['GET','HEAD'], '/route', $handler);

处理器

路由器接受闭包或形式为'controller@method'的字符串作为处理器。后者将作为闭包存储,并尝试在类上调用该静态方法(如果方法在类上可用,是静态的、非抽象的且公开)或尝试实例化该类并调用该方法。在多个路由匹配的情况下,调度器将只调用已注册的第一个路由的处理程序。

// Closures
$router->get('/ping', fn () => 'pong');

$router->get('/sum/{firstNum}/{secondNum}', function ($first, $second) {
    return $first + $second;
});

// Using the controller@method notation
$router->get('/users', 'Users@list');

路由

静态路由

静态路由是没有动态、可变组件的路由。这些路由将与URI完全匹配。

$router->get('/login', 'Login@login');

动态路由

动态路由是某些部分可以变动的路由。路由器通过使用占位符({}表示法)或PCRE正则表达式支持动态路由。

请注意,占位符将接受任何输入,即相当于一个(.*?)正则表达式。在调度路由时,所有占位符值都将传递给匹配的路由的处理程序。

当使用正则表达式时,所有由捕获组返回的变量都将传递给匹配的路由的处理程序。

// 'id' which can be one ore more of any of characters
// will be passed to Users::update() / Users->update()
$router->put('/users/{id}', 'Users@update');

// 'id' which will be one or more digits
// will be passed to Users::update() / Users->update()
$router->get('/artist/(\d+)', 'Users@update');
可选参数

路由的一部分可以通过使用?标记使正则表达式的一部分成为可选的。(/\d+)?

// will match /albums/2023 or /albums/acdc or /albums
$router->get('/albums/{year}?', $handler);

// will match /albums/2023 or /albums
$router->get('/albums(/d+)?', $handler);

路由分组

可以将路由定义为组,该组将为该组中定义的每个路由应用相同的前缀。

$router->group('/users/{id}', function ($router) use ($id) {
    $router->get('/posts', 'Users@getPosts');
    $router->get('/comments', 'Users@getComments');
});

// is equivalent to
$router->get('/users/{id}/posts', 'Users@getPosts');
$router->get('/users/{id}/comments', 'Users@getComments');

未知路由处理器

可以在路由器中定义一个自定义处理器,用于当没有找到路由时。如果有此类处理器已注册,则调度器将在找不到匹配路由时调用此处理器。一次只能定义一个处理器。设置新处理器时,将替换之前的处理器。

$this->router->setRouteNotFoundHandler(fn () => 'Route not found');

// returns 'Route not found'
$this->router->getRouteNotFoundHandler();

路由中间件之前

路由中间件是在实际路由处理程序被调用之前执行的处理器。请注意,将为每个路由执行所有已注册的中间件,并且它们将按注册的顺序执行。

$router->before('GET', '/hello-world', fn () => 'Hello ');
$router->before('GET', '/hello-world', fn () => 'World!');

$beforeRoute = $router->getBeforeMiddleware('GET', 'hello-world');

$result = '';
foreach ($beforeRoute as $middleware) {
    $result .= ($middleware['route']->getHandler())();
}
// $result contains 'Hello World!'

调度器

与路由器一起的派发器是一种基本实现,它执行了路由器的所有功能。即,它执行已注册的中间件,如果注册了“路由未找到”处理程序,则调用它(否则抛出异常),并使用可选的路由参数调用已注册的路由处理程序,并将结果返回给调用者。

$dispatcher = new Dispatcher($router);

$dispatcher->dispatch('GET', '/about-us);

致谢 / 策划

这个路由器/派发器背后的概念和实现受到了 bramus/routerFastRoute 的启发和影响。此外,还受到了 SymfonyLaravel 的启发。