路由

最后更新于:2022-04-01 22:33:52

# 路由 Slim 框架的路由基于 [nikic/fastroute](https://github.com/nikic/FastRoute) 组件进行构建,它格外地快速稳定。 ## 如何创建路由 你在可以使用 `\Slim\App` 实例的代理(proxy)方法来定义应用程序路由。Slim 框架提供了最流行的HTTP方法。 ### Get 路由 使用 Slim 应用程序的 `get()` 方法添加一个只处理 `GET` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->get('/books/{id}', function ($request, $response, $args) { // Show book identified by $args['id'] }); ``` ### POST 路由 使用 Slim 应用程序的 `post()` 方法添加一个只处理 `POST` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->post('/books', function ($request, $response, $args) { // Create new book }); ``` ### PUT 路由 使用 Slim 应用程序的 `put()` 方法添加一个只处理 `PUT` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->put('/books/{id}', function ($request, $response, $args) { // Update book identified by $args['id'] }); ``` ### DELETE 路由 使用 Slim 应用程序的 `delete()` 方法添加一个只处理 `DELETE` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->delete('/books/{id}', function ($request, $response, $args) { // Delete book identified by $args['id'] }); ``` ### OPTIONS 路由 使用 Slim 应用程序的 `options()` 方法添加一个只处理 `OPTIONS` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->options('/books/{id}', function ($request, $response, $args) { // Return response headers }); ``` ### PATCH 路由 使用 Slim 应用程序的 `patch()` 方法添加一个只处理 `PATCH` HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->patch('/books/{id}', function ($request, $response, $args) { // Apply changes to book identified by $args['id'] }); ``` ### 任意路由 使用 Slim 应用程序的 `any()` 方法添加一个可以处理处理所有 HTTP 请求的路由。它接收两个参数: 1. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 2. 路由回调 ``` $app = new \Slim\App(); $app->any('/books/[{id}]', function ($request, $response, $args) { // Apply changes to books or book identified by $args['id'] if specified. // To check which method is used: $request->getMethod(); }); ``` 记住,第二个参数是一个回调。你需要指定一个类(Class,需要一个 `__invoke()` 实现方法。)来替换闭包(Closure)。接着,你可以映射到其他位置: ``` $app->any('/user', 'MyRestfulController'); ``` ### 自定义路由 使用 Slim 应用程序的 `map()` 方法来添加一个可以处理多个 HTTP 请求方法的路由。它接收三个参数: 1. HTTP 方法的数组 2. 路由模式(带有可选的命名占位符)/The route pattern (with optional named placeholders) 3. 路由回调 ``` $app = new \Slim\App(); $app->map(['GET', 'POST'], '/books', function ($request, $response, $args) { // Create new book or list all books }); ``` ## 路由回调 上述的每个路由方法都接收一个回调例程作为其最后一个参数。这个参数可以是任意 PHP 调用(callable),并且它默认接受三个参数。 **请求/Request** 第一个参数是一个 `Psr\Http\Message\ServerRequestInterface` 对象,表示当前的 HTTP 请求。 **响应/Response** 第二个参数是一个 `Psr\Http\Message\ResponseInterface` 对象,表示当前的 HTTP 响应。 **参数数组/Arguments** 第三个参数是一个关联数组,包含包含当前路由的命名占位符。 ### 将内容写入响应 有两种方式可以将内容写入 HTTP 响应。第一钟,可以使用 `echo()` 简单地从路由回调中输出内容。其内容将会呗追加到当前 HTTP 请求对象中。第二种,你可以返回一个 `Psr\Http\Message\ResponseInterface` 对象。 ### 闭包绑定/Closure binding 如果你使用一个`闭包(Closure)`实例作为路由回调,闭包的状态受`Container`实例约束。这意味着你将通过 `$this` 关键字访问闭包内部的 DI 容器实例: ``` $app = new \Slim\App(); $app->get('/hello/{name}', function ($request, $response, $args) { // Use app HTTP cookie service $this->get('cookies')->set('name', [ 'name' => $args['name'], 'expires' => '7 days' ]); }); ``` ## 路由策略 路由回调签名由路由策略决定。默认地,Slim 寄望路由回调来接收请求、响应和由路由占位符参数组成的数组。这称为请求响应策略(RequestResponse strategy)。然而,你可以通过使用另一个不同策略来改变这种寄望。例如,Slim 提供了一个另类的策略,叫做 RequestResponseArgs ,它接收请求和响应,加上由每一个路由占位符组成的单独参数。这里的例子展示了如何使用这个另类的策列;轻松替代了默认`\Slim\Container`提供的 `foundHandler` 依赖: ``` $c = new \Slim\Container(); $c['foundHandler'] = function() { return new \Slim\Handlers\Strategies\RequestResponseArgs(); }; $app = new \Slim\App($c); $app->get('/hello/{name}', function ($request, $response, $name) { return $response->write($name); }); ``` 通过实现 `\Slim\Interfaces\InvocationStrategyInterface` 你可以提供一个你自己的路由策略。 ## 路由占位符 上诉的每个路由方法都会收到一个 URL 模式(URL pattern),它将与当前 HTTP 请求的 URI 相匹配。路由模式将使用命名占位符(named placeholder)来动态匹配 HTTP 请求的URI 片段。 ### 格式 路由模式占位符起始与一个 `{`, 然后是占位符名称, 最后以 `}` 结束。这是一个名为 `name` 的占位符例子: ``` $app = new \Slim\App(); $app->get('/hello/{name}', function ($request, $response, $args) { echo "Hello, " . $args['name']; }); ``` ### 可选的分段 / Optional segments 使一个片段可选,只需用将其放在方括号中: ``` $app->get('/users[/{id}]', function ($request, $response, $args) { // reponds to both `/users` and `/users/123` // but not to `/users/` }); ``` 支持多个可选参数嵌套: ``` $app->get('/news[/{year}[/{month}]]', function ($request, $response, $args) { // reponds to `/news`, `/news/2016` and `/news/2016/03` }); ``` 对于数目不确定的可选参数,可以这样做: ``` $app->get('/news[/{params:.*}]', function ($request, $response, $args) { $params = explode('/', $request->getAttribute('params')); // $params is an array of all the optional segments }); ``` 在这个例子中,`/news/2016/03/20` 的 URI 将使得 `$params` 数组包含三个元素:`['2016', '03', '20']`. ### 正则表达式匹配 默认地,占位符被写在 `{}` 之中,并可以接收任意值。然而,占位符同样可以要求 HTTP 请求 URI 匹配特定的正则表达式。如果当前的HTTP 请求URI 不能与占位符的正则表达式匹配,路由路由将不会启动。下面这个示例占位符要求 `id` 必须是个数字: ``` $app = new \Slim\App(); $app->get('/users/{id:[0-9]+}', function ($request, $response, $args) { // Find user identified by $args['id'] }); ``` ## 路由名称 应用程序的路由可以被指定一个名称。这非常有用,如果你想要使用路由的 `pathFor()` 方法以编程的形式生成一个特定路由的 URL 。上述的每个路由方法都会返回一个 `\Slim\Route` 对象,这个对象带来了 `setName()` 方法。 ``` $app = new \Slim\App(); $app->get('/hello/{name}', function ($request, $response, $args) { echo "Hello, " . $args['name']; })->setName('hello'); ``` 使用应用程序路由的 `pathFor()` 方法,为已命名的路由生成一个 URL 。 ``` echo $app->router->pathFor('hello', [ 'name' => 'Josh' ]); // Outputs "/hello/Josh" ``` 路由的 `pathFor()` 方法接收两个参数: 1. 路由名称 2. 由路由模式占位符及替换值组成的关联数组。 ## 路由组 为了帮助将路由整理成条理分明的路由组, `\Slim\App` 还提供了一个 `group()` 方法。 每个路由组的路由模式预置于路由或路由组中的路由组,路由组模式的任何占位符参数最终使得嵌套的路由都是可用的: ``` $app = new \Slim\App(); $app->group('/users/{id:[0-9]+}', function () { $this->map(['GET', 'DELETE', 'PATCH', 'PUT'], '', function ($request, $response, $args) { // Find, delete, patch or replace user identified by $args['id'] })->setName('user'); $this->get('/reset-password', function ($request, $response, $args) { // Route for /users/{id:[0-9]+}/reset-password // Reset the password for user identified by $args['id'] })->setName('user-password-reset'); }); ``` 记住,在路由组闭包的内部,使用 `$this` 替代 `$app` 。Slim 将闭包绑定到应用程序实例,就像路由回调的情况那样。 ## 路由中间件 你可以将中间件与任意路由或路由组相连接。 [了解更多](/docs/concepts/middleware.html). ## 容器识别 / Container Resolution 你不必限于为路由定义函数。在 Slim 中,有一些不同的方式来定义你的路由行为函数。 除了函数外,你还可以使用: - 可调用的类 - `Class:method` 这个函数由 Slim 的 Callable 解角器(Resolver) 类提供支持。它将字符串入口(entry)转变为函数调用。例如: ``` $app->get('/home', '\HomeController:home'); ``` 在上面这段代码中,我们定义了一个 `/home` 路由,并告诉 Slim 执行 `\HomeController` 类中的 `home()` 方法。 Slim 首先在容器中寻找 `\HomeController` 的入口,如果找到了,它将使用该实例。否则,它将它的构造函数,并将容器作为第一个参数。一旦这个类的实例创建了,它将使用你已定义的策略(Strategy)去调用指定的方法。 作为另一种办法,你可以使用一个可调用的(invokable)类,比如: ``` class MyAction { protected $ci; //Constructor public function __construct(ContainerInterface $ci) { $this->ci = $ci; } public function __invoke($request, $response, $args) { //your code //to access items in the container... $this->ci->get(''); } } ``` 你可以这样使用这个累: ``` $app->get('/home', '\MyAction'); ``` 在更为传统的 MVC 方法中,你构建包含许多行为(actions)的控制器来替代只能处理一个行为的可调用类。 ``` class MyController { protected $ci; //Constructor public function __construct(ContainerInterface $ci) { $this->ci = $ci; } public function method1($request, $response, $args) { //your code //to access items in the container... $this->ci->get(''); } public function method2($request, $response, $args) { //your code //to access items in the container... $this->ci->get(''); } public function method3($request, $response, $args) { //your code //to access items in the container... $this->ci->get(''); } } ``` 你可以这样使用控制器方法: ``` $app->get('/method1', '\MyController:method1'); $app->get('/method2', '\MyController:method2'); $app->get('/method3', '\MyController:method3'); ```
';