路由
概述
基本用法
高级用法
如果您想通过容器(PSR-11、PHP-DI、Dice 等)使用依赖注入,则唯一可用的路由类型是直接自己创建对象并使用容器创建您的对象,或者使用字符串定义要调用的类和方法。您可以转到
依赖注入
页面获取更多信息。
以下是一个快速示例:
use flight\database\PdoWrapper;
// Greeting.php
class Greeting
protected PdoWrapper $pdoWrapper;
public function __construct(PdoWrapper $pdoWrapper) {
$this->pdoWrapper = $pdoWrapper;
public function hello(int $id) {
// 使用 $this->pdoWrapper 做些什么
$name = $this->pdoWrapper->fetchField("SELECT name FROM users WHERE id = ?", [ $id ]);
echo "Hello, world! My name is {$name}!";
// index.php
// 使用所需的任何参数设置容器
// 请参阅依赖注入页面以获取有关 PSR-11 的更多信息
$dice = new \Dice\Dice();
// 不要忘记使用 '$dice = ' 重新赋值变量!!!!
$dice = $dice->addRule('flight\database\PdoWrapper', [
'shared' => true,
'constructParams' => [
'mysql:host=localhost;dbname=test',
'root',
'password'
// 注册容器处理程序
Flight::registerContainerHandler(function($class, $params) use ($dice) {
return $dice->create($class, $params);
// 像往常一样定义路由
Flight::route('/hello/@id', [ 'Greeting', 'hello' ]);
Flight::route('/hello/@id', 'Greeting->hello');
Flight::route('/hello/@id', 'Greeting::hello');
Flight::start();
路由别名
通过为路由分配别名,您可以在应用程序中动态调用该别名,以便稍后在代码中生成(例如:HTML 模板中的链接,或生成重定向 URL)。
Flight::route('/users/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
Flight::route('/users/@id', function($id) { echo 'user:'.$id; })->setAlias('user_view');
// 稍后在代码中的某处
class UserController {
public function update() {
// 保存用户的代码...
$id = $user['id']; // 例如 5
$redirectUrl = Flight::getUrl('user_view', [ 'id' => $id ]); // 将返回 '/users/5'
Flight::redirect($redirectUrl);
这在 URL 发生变化时特别有用。在上面的示例中,假设用户已移动到
/admin/users/@id
。
使用别名设置路由后,您无需在代码中查找所有旧 URL 并更改它们,因为别名现在将返回
/admin/users/5
,如上面的示例。
路由别名在组中仍然有效:
Flight::group('/users', function() {
Flight::route('/@id', function($id) { echo 'user:'.$id; }, false, 'user_view');
Flight::route('/@id', function($id) { echo 'user:'.$id; })->setAlias('user_view');
});
路由分组和中间件
有时您可能想将相关路由分组在一起(例如
/api/v1
)。
您可以通过使用
group
方法来实现:
Flight::group('/api/v1', function () {
Flight::route('/users', function () {
// 匹配 /api/v1/users
Flight::route('/posts', function () {
// 匹配 /api/v1/posts
});
您甚至可以嵌套组的组:
Flight::group('/api', function () {
Flight::group('/v1', function () {
// Flight::get() 获取变量,它不设置路由!请参阅下面的对象上下文
Flight::route('GET /users', function () {
// 匹配 GET /api/v1/users
Flight::post('/posts', function () {
// 匹配 POST /api/v1/posts
Flight::put('/posts/1', function () {
// 匹配 PUT /api/v1/posts
Flight::group('/v2', function () {
// Flight::get() 获取变量,它不设置路由!请参阅下面的对象上下文
Flight::route('GET /users', function () {
// 匹配 GET /api/v2/users
});
您仍然可以使用以下方式与
Engine
对象一起使用路由分组:
$app = Flight::app();
$app->group('/api/v1', function (Router $router) {
// 使用 $router 变量
$router->get('/users', function () {
// 匹配 GET /api/v1/users
$router->post('/posts', function () {
// 匹配 POST /api/v1/posts
注意: 这是使用 $router 对象定义路由和组的首选方法。
使用中间件的分组
您也可以为路由组分配中间件:
Flight::group('/api/v1', function () {
Flight::route('/users', function () {
// 匹配 /api/v1/users
}, [ MyAuthMiddleware::class ]); // 或 [ new MyAuthMiddleware() ] 如果您想使用实例
请参阅 组中间件 页面的更多细节。
您现在可以使用
stream()
或
streamWithHeaders()
向客户端流式传输响应。
这对于发送大文件、长时间运行的进程或生成大响应很有用。
流式传输路由的处理方式与常规路由略有不同。
注意:
流式响应仅在您将
flight.v2.output_buffering
设置为
false
时可用。
手动标头的流式传输
您可以通过在路由上使用
stream()
方法向客户端流式传输响应。如果您
这样做,您必须在向客户端输出任何内容之前手动设置所有标头。
这是使用
header()
php 函数或
Flight::response()->setRealHeader()
方法完成的。
Flight::route('/@filename', function($filename) {
$response = Flight::response();
// 显然您会清理路径什么的。
$fileNameSafe = basename($filename);
// 如果您在路由执行后有额外的标头要设置
// 您必须在回显任何内容之前定义它们。
// 它们必须全部是 header() 函数的原始调用或
// Flight::response()->setRealHeader() 的调用
header('Content-Disposition: attachment; filename="'.$fileNameSafe.'"');
$response->setRealHeader('Content-Disposition: attachment; filename="'.$fileNameSafe.'"');
$filePath = '/some/path/to/files/'.$fileNameSafe;
if (!is_readable($filePath)) {
Flight::halt(404, 'File not found');
// 如果您愿意,手动设置内容长度
header('Content-Length: '.filesize($filePath));
$response->setRealHeader('Content-Length: '.filesize($filePath));
// 以读取的方式将文件流式传输到客户端
readfile($filePath);
// 这是这里的魔法行
})->stream();
带标头的流式传输
您也可以使用
streamWithHeaders()
方法在开始流式传输之前设置标头。
Flight::route('/stream-users', function() {
// 您可以在这里添加任何额外的标头
// 您只需使用 header() 或 Flight::response()->setRealHeader()
// 无论您如何拉取数据,仅作为示例...
$users_stmt = Flight::db()->query("SELECT id, first_name, last_name FROM users");
echo '{';
$user_count = count($users);
while($user = $users_stmt->fetch(PDO::FETCH_ASSOC)) {
echo json_encode($user);
if(--$user_count > 0) {
echo ',';
// 这是在将数据发送到客户端时必需的
ob_flush();
echo '}';
// 这是您在开始流式传输之前设置标头的方式。
})->streamWithHeaders([
'Content-Type' => 'application/json',
'Content-Disposition' => 'attachment; filename="users.json"',
// 可选状态代码,默认 200
'status' => 200
]);
另请参阅
-
中间件
- 使用中间件与路由进行身份验证、日志记录等。
-
依赖注入
- 简化路由中的对象创建和管理。
-
为什么使用框架?
- 理解使用像 Flight 这样的框架的好处。
-
扩展
- 如何使用自己的功能扩展 Flight,包括
notFound
方法。
-
php.net: preg_match
- PHP 用于正则表达式匹配的函数。
-
路由参数按顺序匹配,而不是按名称。确保回调参数顺序与路由定义匹配。
-
使用
Flight::get()
不会定义路由;对于路由,请使用
Flight::route('GET /...')
或组中的 Router 对象上下文(例如
$router->get(...)
)。
-
executedRoute 属性仅在路由执行后设置;在执行前为 NULL。
-
流式传输需要禁用遗留 Flight 输出缓冲功能(
flight.v2.output_buffering = false
)。
-
对于依赖注入,只有某些路由定义支持基于容器的实例化。
更新日志