mindplay/timber

Timber是一个具有正则表达式支持、高性能以及开发者友好、可读性强的API的请求路由器

3.0.0 2024-03-28 08:48 UTC

This package is auto-updated.

Last update: 2024-08-28 09:39:14 UTC


README

PHP Version Build status

Timber是一个具有正则表达式支持、高性能以及开发者友好、可读性强的API的路由器库。

安装

使用composer require mindplay/timber安装最新版本

介绍

此包提供了一个最基础的路由设施:一个注册路径模式的地方,以及将这些模式解析到控制器名称的方法。

使用方法

以下示例中,我们假设处理程序(通过get()post()等附加)是控制器类名 - 在您的应用中,它们可能是DI容器中的组件ID、文件名或其他您喜欢的任何东西。

路由器的基本用法如下

use mindplay\timber\Router;
use mindplay\timber\Result;
use mindplay\timber\Error;

require __DIR__ . '/vendor/autoload.php';

$router = new Router();

// Defining route for one HTTP method
$router->route('news')->get(ListNews::class);

// Defining route for several HTTP methods
$router->route('/')->get(ShowHomePage::class)->post(PostComments::class);

// Defining a route with regular expression param
$news_route = $router->route('news/<id:^[0-9]+$>')->get(ShowNews::class);

// Defining another route with symbolic param
$router->route('users/<username:slug>')->get(ShowUser::class);

// Defining static route that conflicts with previous route, but static routes have high priority
$router->route('news/all')->get(ShowAllNews::class);

// Defining a wildcard route, matching e.g. "categories/foo", "categories/foo/bar", etc.:
$router->route('categories/<path:*>')->get(ShowCategory::class);

// Resolve HTTP method and URL:

$method = 'GET';
$url = '/news/1';

$result = $router->resolve($method, $url);

if ($result instanceof Error) {
    header("HTTP/1.1 {$result->status} ${result->message}");
    // ...error response here...
    return;
} else {
    // ...dispatch $result->handler with $result->params...
}

如果您正在构建属于同一父路由的一组路由,您可以从父路由继续构建 - 例如

$admin = $router->route('admin')->get(AdminMenu::class);

$admin->route('users')->get(AdminUserList::class);
$admin->route('groups')->get(AdminGroupList::class);

此示例将/admin路由到AdminMenu,并将/admin/users路由到AdminUserList等。

此功能还支持模块化重用路由定义 - 例如

$build_comment_routes = function (Route $parent) {
    $parent->route('comments')->get(ShowComments::class);
    $parent->route('comments/new')->get(ShowCommentForm::class)->post(PostComment::class);
}

$build_comment_routes($router->route('articles/<article_id:int>'));
$build_comment_routes($router->route('products/<product_id:int>'));

此示例为显示和发布两个不同父路由的评论创建了两个相同的一组路由。

优化

您可以保存和恢复已定义的路由

use mindplay\timber\Router;

require __DIR__ . '/vendor/autoload.php';

$router = new Router();
$router->route('/')->get(ShowHomePage::class);
$router->route('/news')->get(ShowNews::class);

$routes = $router->getRoutes();

$anotherRouter = new Router();
$anotherRouter->setRoutes($routes);

$method = 'GET';
$url = '/news';

$result = $anotherRouter->resolve($method, $url);

目的是,您可以序列化和反序列化已构建的路由,并将它们存储在某个地方的缓存中,以避免初始化开销。对于大多数项目,这将被视为一个微优化 - 构建大量(数百或数千)路由的开销可能会在非常大的模块化项目中变得值得。

黑客

要运行测试套件,请导航到项目根目录并输入

php test/test.php

设计备注

在开发此库的过程中,我们识别了一个设计问题,这要求我们做出权衡。这个库曾经一度具有URL创建功能,但经过仔细权衡利弊,我们决定放弃这个功能,转而支持更简单的实现和缓存支持。

探索和评估了三种不同的方法 - 我们的白板总结了我们认为的优缺点,并且没有URL创建的方法是我们一致最喜欢的方法,因为它在库和用例中都带来了最大的简单性,并且支持缓存。

第一个权衡是我们不能使用闭包(无法序列化)因此我们无法在路由和控制器/操作/参数之间获得任何直接的静态耦合 - 我们通过使用::class常量获得了对控制器类名的静态耦合。

另一个权衡是,我们无法在路由器本身内实现URL创建功能,因为这会导致复杂性增加(如按照情况1中添加命名路由注册表)或阻止缓存(如按照情况2)。经过一番讨论,我们决定URL创建只提供微小的好处,确保URL创建与定义的模式一致;但是,我们也重视根据具体情况使用更简单的代码完全自定义URL创建的自由(如按照情况3)。因此,URL创建功能的缺失实际上可以被视为一种优势。

致谢

Timber项目最初是TreeRoute项目的分支,由Vadim Baryshev创建,API和功能集迅速发展成为一个全新的项目。从原始分支中保留下来的是出色的性能。