1 Star 0 Fork 21

hex64 / php-srouter

forked from inhere / php-srouter 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

php simple router

非常轻量级的路由器。无依赖、简洁、速度快、自定义性强

  • 轻量级且速度快,查找速度不受路由数量的影响
  • 支持路由参数定义,以及路由选项(比如设定 domains、schema等检查限制)
  • 支持请求方法: GET POST PUT DELETE HEAD OPTIONS ...
  • 支持事件: found notFound execStart execEnd execError. 当触发事件时你可以做一些事情(比如记录日志等)
  • 支持动态获取action名。支持设置方法执行器(actionExecutor),通过方法执行器来自定义调用真实请求方法.
  • 支持自动匹配路由到控制器就像 yii 一样, 请参看配置项 autoRoute.
  • 支持通过方法 SRouter::dispatch($path, $method) 手动调度一个路由
  • 你也可以不配置任何东西, 它也能很好的工作

EN README

项目地址

安装

  • composer
{
    "require": {
        "inhere/sroute": "dev-master"
    }
}
  • 直接拉取
git clone https://github.com/inhere/php-srouter.git // github
git clone https://git.oschina.net/inhere/php-srouter.git // git@osc

压测

自动生成了1000条路由,每条有9个参数位,分别测试1000次的

  • 第一条路由匹配
  • 最后一条路由匹配
  • 不会匹配到的路由

压测结果

Worst-case matching

This benchmark matches the last route and unknown route. It generates a randomly prefixed and suffixed route in an attempt to thwart any optimization. 1,000 routes each with 9 arguments.

This benchmark consists of 14 tests. Each test is executed 1,000 times, the results pruned, and then averaged. Values that fall outside of 3 standard deviations of the mean are discarded.

Test Name Results Time + Interval Change
ORouter - unknown route (1000 routes) 988 0.0000120063 +0.0000000000 baseline
ORouter - last route (1000 routes) 988 0.0000122867 +0.0000002804 2% slower
SRouter - unknown route (1000 routes) 983 0.0000123633 +0.0000003570 3% slower
SRouter - last route (1000 routes) 998 0.0000142205 +0.0000022142 18% slower
Symfony2 Dumped - last route (1000 routes) 990 0.0000468579 +0.0000348516 290% slower
Symfony2 Dumped - unknown route (1000 routes) 995 0.0000490268 +0.0000370205 308% slower
FastRoute - unknown route (1000 routes) 968 0.0001358227 +0.0001238164 1031% slower
FastRoute(cached) - last route (1000 routes) 999 0.0001397746 +0.0001277683 1064% slower
FastRoute(cached) - unknown route (1000 routes) 960 0.0001424064 +0.0001304001 1086% slower
FastRoute - last route (1000 routes) 999 0.0001659009 +0.0001538946 1282% slower
Pux PHP - unknown route (1000 routes) 964 0.0013507533 +0.0013387470 11150% slower
Pux PHP - last route (1000 routes) 999 0.0014749475 +0.0014629412 12185% slower
Symfony2 - unknown route (1000 routes) 979 0.0038350259 +0.0038230196 31842% slower
Symfony2 - last route (1000 routes) 999 0.0040060059 +0.0039939995 33266% slower

First route matching

This benchmark tests how quickly each router can match the first route. 1,000 routes each with 9 arguments.

This benchmark consists of 7 tests. Each test is executed 1,000 times, the results pruned, and then averaged. Values that fall outside of 3 standard deviations of the mean are discarded.

Test Name Results Time + Interval Change
Pux PHP - first route(1000) 993 0.0000105502 +0.0000000000 baseline
ORouter - first route(1000) 984 0.0000118334 +0.0000012832 12% slower
SRouter - first route(1000) 982 0.0000118473 +0.0000012971 12% slower
FastRoute(cached) - first route(1000) 999 0.0000143361 +0.0000037859 36% slower
FastRoute - first route(1000) 999 0.0000143980 +0.0000038477 36% slower
Symfony2 Dumped - first route 993 0.0000350874 +0.0000245372 233% slower
Symfony2 - first route 999 0.0000630564 +0.0000525061 498% slower

使用

  • Inhere\Route\SRouter 是静态类版本
  • Inhere\Route\ORouter 是对象版本

两个类的方法名和参数都是一样的

首先, 导入类

use Inhere\Route\SRouter;

添加路由

// 匹配 GET 请求. 处理器是个闭包 Closure
SRouter::get('/', function() {
    echo 'hello';
});

// 匹配参数 'test/john'
SRouter::get('/test/{name}', function($params) {
    echo $params['name']; // 'john'
}, [
    'params' => [
        'name' => '\w+', // 添加参数匹配限制。若不添加对应的限制,将会自动设置为匹配除了'/'外的任何字符
    ]
]);

// 可选参数支持。匹配  'hello' 'hello/john'
SRouter::get('/hello[/{name}]', function() {
    echo $params['name'] ?? 'No input'; // 'john'
}, [
    'params' => [
        'name' => '\w+', // 添加参数匹配限制
    ]
]);

// 匹配 POST 请求
SRouter::post('/user/login', function() {
    var_dump($_POST);
});

// 匹配 GET 或者 POST
SRouter::map(['get', 'post'], '/user/login', function() {
    var_dump($_GET, $_POST);
});

// 允许任何请求方法
SRouter::any('/home', function() {
    echo 'hello, you request page is /home';
});
SRouter::any('/404', function() {
    echo "Sorry,This page not found.";
});

// 路由组
SRouter::group('/user', function () {
    SRouter::get('/', function () {
        echo 'hello. you access: /user/';
    });
    SRouter::get('/index', function () {
        echo 'hello. you access: /user/index';
    });
});

如果配置了 'ignoreLastSep' => true, '/index' 等同于 '/index/'

添加路由方法

public function map(string|array $methods, string $route, mixed $handler, array $opts = [])

添加路由方法

其他的添加路由方法底层都是调用的 map() 方法,除了没有第一个参数外,其他参数都是一样的

  • $methods string|array 请求的METHOD. e.g GET ['GET', 'POST]
  • $route string 定义的路由字符串 e.g /user/login /article/{id}
  • $handler string|object 对应路由的处理者
  • $opts array 选项设置,可以添加自定义的数据。匹配成功会将选项数据返回(e.g middleware, domains),自己再做进一步验证等。下面是已使用的选项
    • params 添加路由时设置的参数匹配信息, 若有的话 e.g 'name' => '\w+'
    • defaults 有可选参数时,可以设置默认值

一个较为完整的示例:

提示: 若不在选项中设置参数匹配,那么参数将会匹配除了 '/' 之外的任何字符

$router->map(['get', 'post'], '/im/{name}[/{age}]', function(array $params) {
    var_dump($params);
}, [
    // 设置参数匹配
    'params' => [
        'name' => '\w+',
        'age' => '\d+',
    ],
    'defaults' => [
        'age' => 20, // 给可选参数 age 添加一个默认值
    ]
    
    // 可添加更多自定义设置
    'middleware' => ['AuthCheck'],
    'domains' => ['localhost'],
    ... ...
]);

Now, 访问 /im/john/18 或者 /im/john 查看效果

自动匹配路由

支持根据请求的URI自动匹配路由(就像 yii 一样), 需配置 autoRoute.

    'autoRoute' => 1, // 启用
    'controllerNamespace' => 'App\\Controllers', // 控制器类所在命名空间
    'controllerSuffix' => 'Controller', // 控制器类后缀

请参看示例 example 中的使用

此时请求没有配置路由的 /demo /demo/test。将会自动尝试从 App\\Controllers 命名空间下去查找 DemoController

查找逻辑是

  • 只有一节的(如/demo),直接定义它为控制器类名进行查找
  • 大于等于两节的默认先认为最后一节是控制器类名,进行查找
  • 若失败,再尝试将倒数第二节认为是控制器名,最后一节是action名

匹配所有

配置 intercept 可用于拦截所有请求。 (例如网站维护时)

可允许配置 intercept 的值为

  • 路由path
    'intercept' => '/about', // a route path

将会直接执行此路由后停止执行

  • 回调
    'intercept' => function () {
        echo '系统维护中 :)';
    },

将会直接执行此回调后停止执行

设置路由配置

// set config
SRouter::setConfig([
    'ignoreLastSep' => true,    
    'autoRoute' => 1,
    'controllerNamespace' => 'app\\controllers',
    'controllerSuffix' => 'Controller',
]);

NOTICE: 必须在添加路由之前调用 SRouter::setConfig()

路由匹配

array public function match($path, $method)
  • $path string 请求的URI path
  • $method string 请求的request method
  • 返回 array 返回匹配结果信息

示例

根据请求的 URI path 和 请求 METHOD 查找匹配我们定义的路由信息。

$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];

$route = SRouter::match($path, $method);

将会返回如下格式的信息. 可以根据此信息进行 判断匹配是否成功 -> 路由调度

[
    // 路由匹配结果状态. 
    // 可能为: RouterInterface::FOUND, RouterInterface::NOT_FOUND, RouterInterface::METHOD_NOT_ALLOWED
    INT, 
    
    // 格式化后的 $path 的返回(会去除多余的空白,'/'等字符)
    'URI PATH', 
    
    // 路由信息。 匹配失败时(RouterInterface::NOT_FOUND)为 null 
    [
        // (可能存在)配置的请求 METHOD。 自动匹配时无此key
        'method' => 'GET', 
        
        // 此路由的 handler callback
        'handler' => 'handler', 
        
        // (可能存在) 有参数匹配的路由匹配成功后,会将参数值放入这里
        'matches' => ['name' => value ],
        
        // 此路由的自定义选项信息. 可能为空
        // - params - 来自添加路由时设置的参数匹配信息, 若有的话
        // - defaults - 有可选参数时,可以设置默认值
        // 还可以自定义追加此路由的选项:如下经供参考
        // - domains 允许访问路由的域名
        // - schema 允许访问路由的schema
        // - enter 进入路由的事件回调
        // ... ...
        'option' => [
            'params' => [],
            'defaults' => [],

            // 'domains' => null,
            // 'schema' => null, // ['http','https'],
            // route event. custom design ...
            // 'enter' => null,
            // 'leave' => null,
        ], 
        
    ],
]

路由调度

已内置了一个路由调度器 Inhere\Route\Dispatcher

use Inhere\Route\Dispatcher;

$dispatcher = new Dispatcher([
    'dynamicAction' => true,
]);

设置事件处理

// 成功匹配路由
$dispatcher->on(Dispatcher::ON_FOUND, function ($uri, $cb) use ($app) {
    $app->logger->debug("Matched uri path: $uri, setting callback is: " . is_string($cb) ? $cb : get_class($cb));
});

// 当匹配失败, 重定向到 '/404'
$dispatcher->on('notFound', '/404');
// 或者, 当匹配失败, 输出消息...
$dispatcher->on('notFound', function ($uri) {
    echo "the page $uri not found!";
});

使用控制器方法

通过@符号连接控制器类和方法名可以指定执行方法。

SRouter::get('/', app\controllers\Home::class);

SRouter::get('/index', 'app\controllers\Home@index');
SRouter::get('/about', 'app\controllers\Home@about');

NOTICE: 若第二个参数仅仅是个 类,将会尝试执行通过 defaultAction 配置的默认方法

动态匹配控制器方法

动态匹配控制器方法, 需配置 'dynamicAction' => true

NOTICE: 使用动态匹配控制器方法, 应当使用 any() 添加路由. 即此时无法限定请求方法 REQUEST_METHOD

// 访问 '/home/test' 将会执行 'app\controllers\Home::test()'
SRouter::any('/home/{any}', app\controllers\Home::class);

// 可匹配 '/home', '/home/test' 等
SRouter::any('/home[/{name}]', app\controllers\Home::class);

NOTICE: 上面两个的区别是 第一个无法匹配 /home

使用方法执行器

配置 actionExecutor 为你需要的方法名,例如配置为 'actionExecutor' => 'run',那所有的方法请求都会提交给此方法。 会将真实的 action 作为参数传入run($action), 需要你在此方法中调度来执行真正的请求方法。

NOTICE: 在你需要将路由器整合到自己的框架时很有用

示例:

// 访问 '/user', 将会调用 app\controllers\User::run('')
SRouter::get('/user', 'app\controllers\User');

// 访问 '/user/profile', 将会调用 app\controllers\User::run('profile')
SRouter::get('/user/profile', 'app\controllers\User');

// 同时配置 'actionExecutor' => 'run' 和 'dynamicAction' => true,
// 访问 '/user', 将会调用 app\controllers\User::run('')
// 访问 '/user/profile', 将会调用 app\controllers\User::run('profile')
SRouter::any('/user[/{name}]', 'app\controllers\User');

开始路由匹配和调度

SRouter::dispatch($dispatcher);
// $router->dispatch($dispatcher);

运行示例

示例代码在 examples 下。

  • 静态版本

你可以通过 php -S 127.0.0.1:5670 examples/static.php 来运行一个测试服务器, 现在你可以访问 http://127.0.0.1:5670

  • 对象版本

你可以通过 php -S 127.0.0.1:5670 examples/object.php 来运行一个测试服务器, 现在你可以访问 http://127.0.0.1:5671

License

MIT

我的其他项目

inhere/console github git@osc

功能丰富的命令行应用,命令行工具库

inhere/redis github git@osc

简单的redis操作客户端包装库

inhere/php-validate github git@osc

一个简洁小巧且功能完善的php验证库。仅有几个文件,无依赖。

inhere/http github git@osc

http 工具库(request 请求 response 响应 curl curl请求库,有简洁、完整和并发请求三个版本的类)

The MIT License (MIT) Copyright (c) 2015 Noah Buscher Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

非常轻量级的的路由器。速度快,查找速度不受路由数量的影响。支持请求方法: GET POST PUT DELETE HEAD OPTIONS. 支持事件: found notFound... 当触发事件时你可以做一些事情(比如记录日志等),支持自动匹配路由到控制器就像 yii 一样 ... ... 展开 收起
PHP
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
PHP
1
https://gitee.com/hex64/php-srouter.git
git@gitee.com:hex64/php-srouter.git
hex64
php-srouter
php-srouter
master

搜索帮助