{"id":17249466,"url":"https://github.com/inhere/php-sroute","last_synced_at":"2025-05-05T22:16:38.363Z","repository":{"id":40693624,"uuid":"84031739","full_name":"inhere/php-sroute","owner":"inhere","description":"A very lightweight and fast speed PHP request router. 非常快速且轻量的请求匹配路由器。无依赖、简洁、自定义性强，查找匹配速度快","archived":false,"fork":false,"pushed_at":"2025-04-20T08:03:41.000Z","size":1360,"stargazers_count":72,"open_issues_count":4,"forks_count":14,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-20T08:41:34.934Z","etag":null,"topics":["dispatch","matchall","php","php-router","route","router","routing","web-router"],"latest_commit_sha":null,"homepage":"https://inhere.github.io/php-sroute/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/inhere.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-03-06T05:01:15.000Z","updated_at":"2025-04-20T08:02:11.000Z","dependencies_parsed_at":"2024-03-09T08:26:02.750Z","dependency_job_id":"9a2cbc79-685f-4535-b95b-d25eb3e413f8","html_url":"https://github.com/inhere/php-sroute","commit_stats":{"total_commits":220,"total_committers":4,"mean_commits":55.0,"dds":0.08636363636363631,"last_synced_commit":"f7ed8f7f81a86d35026678bafa6267119eea7679"},"previous_names":["inhere/php-srouter"],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inhere%2Fphp-sroute","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inhere%2Fphp-sroute/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inhere%2Fphp-sroute/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inhere%2Fphp-sroute/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/inhere","download_url":"https://codeload.github.com/inhere/php-sroute/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252584334,"owners_count":21771945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dispatch","matchall","php","php-router","route","router","routing","web-router"],"created_at":"2024-10-15T06:44:26.524Z","updated_at":"2025-05-05T22:16:38.270Z","avatar_url":"https://github.com/inhere.png","language":"PHP","readme":"# SRoute\n\n[![License](https://img.shields.io/packagist/l/inhere/sroute.svg?style=flat-square)](LICENSE)\n[![PHP Version](https://img.shields.io/packagist/php-v/inhere/sroute.svg?colorB=green)](https://packagist.org/packages/inhere/sroute)\n[![Latest Stable Version](http://img.shields.io/packagist/v/inhere/sroute.svg)](https://packagist.org/packages/inhere/sroute)\n[![Unit-tests](https://github.com/inhere/php-sroute/actions/workflows/php.yml/badge.svg)](https://github.com/inhere/php-sroute/actions)\n[![Coverage Status](https://coveralls.io/repos/github/inhere/php-sroute/badge.svg?branch=master)](https://coveralls.io/github/inhere/php-sroute?branch=master)\n\n非常快速且轻量的请求匹配路由器, web 路由框架。\n\n  - 无依赖、简洁、速度快、功能完善\n  - 轻量级且速度快，查找速度不受路由数量的影响\n  - 支持路由组, 支持路由参数定义，以及丰富的自定义路由选项\n  - 支持给指定的路由命名，可根据名称拿到注册的路由对象\n  - 支持请求方法: `GET` `POST` `PUT` `DELETE` `HEAD` `OPTIONS` ...\n  - 支持自动匹配路由到控制器就像 Yii 一样, 请参看配置项 `autoRoute` (不推荐)\n  - 压测对比数据请看[路由测试](#ab-test)\n\n**多个版本：**\n\n\u003e 不同的版本有稍微的区别以适应不同的场景\n\n- `Router` 通用版本，也是后几个版本的基础类，适用于所有的情况。\n- `SRouter` 静态类版本。`Router` 的简单包装，通过静态方法使用(方便小应用快速使用)\n- `CachedRouter` 继承自`Router`，支持路由缓存的版本，可以 **缓存路由信息到文件**\n  - 适合php-fpm 环境使用(有缓存将会省去每次的路由收集和解析消耗) \n- `PreMatchRouter` 继承自`Router`，预匹配路由器。**当应用的静态路由较多时，将拥有更快的匹配速度**\n  - 适合php-fpm 环境，php-fpm 情形下，实际上我们在收集路由之前，已经知道了路由path和请求动作METHOD\n- `ServerRouter` 继承自`Router`，服务器路由。内置支持**动态路由临时缓存**. 适合 `swoole` 等**常驻内存应用**使用\n  - 最近请求过的动态路由将会缓存为一个静态路由信息，下次相同路由将会直接匹配命中\n\n**内置调度器：**\n\n- 支持事件: `found` `notFound` `execStart` `execEnd` `execError`. 当触发事件时你可以做一些事情(比如记录日志等)\n- 支持动态获取`action`名。支持设置方法执行器(`actionExecutor`)，通过方法执行器来自定义调用真实请求方法. \n- 支持通过方法 `$router-\u003edispatch($path, $method)` 手动调度一个路由\n- 你即使不配置任何东西, 它也能很好的工作\n\n**路由器管理**\n\n`RouterManager` 当需要在一个项目里处理多个域名下的请求时，方便的根据不同域名配置多个路由器\n\n**[EN README](README_en.md)**\n\n## 项目地址\n\n- **github** https://github.com/inhere/php-sroute.git\n- **gitee** https://gitee.com/inhere/php-sroute.git\n\n## 安装\n\n\u003e required PHP 8.0+\n\n- composer 命令\n\n```php\ncomposer require inhere/sroute\n```\n\n- composer.json\n\n```json\n{\n    \"require\": {\n        \"inhere/sroute\": \"dev-master\"\n    }\n}\n```\n\n- 直接拉取\n\n```bash\ngit clone https://github.com/inhere/php-sroute.git // github\n```\n\n\u003ca name=\"ab-test\"\u003e\u003c/a\u003e\n## 压测\n\n自动生成了1000条路由，每条有9个参数位，分别测试1000次的 \n\n- 第一条路由匹配\n- 最后一条路由匹配\n- 不存在的路由匹配\n\n详细的测试代码请看仓库 https://github.com/ulue/php-router-benchmark\n\n- 压测日期 **2018.11.19**\n- An example route: `/9b37eef21e/{arg1}/{arg2}/{arg3}/{arg4}/{arg5}/{arg6}/{arg7}/{arg8}/{arg9}/bda37e9f9b`\n\n## Worst-case matching\n\nThis 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.\n\nThis 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.\n\nTest Name | Results | Time(ms) | + Interval | Change\n------------------ | ------- | ------- | ---------- | -----------\n**inhere/sroute(Router)** - unknown route(1000 routes)  | 990 | 0.002031 | +0.000871 | 75% slower\ninhere/sroute(SRouter) - unknown route(1000 routes)     | 994 | 0.002895 | +0.001736 | 150% slower\n**inhere/sroute(Router)** - last route(1000 routes)     | 997 | 0.005300 | +0.004141 | 357% slower\ninhere/sroute(SRouter) - last route(1000 routes)        | 997 | 0.006467 | +0.005308 | 458% slower\nsymfony/routing(cached) - unknown route(1000 routes)    | 976 | 0.012777 | +0.011618 | 1002% slower\nsymfony/routing(cached) - last route(1000 routes)       | 996 | 0.013608 | +0.012449 | 1074% slower\nmindplay/timber - last route(1000 routes)               | 998 | 0.017211 | +0.016052 | 1385% slower\nFastRoute - unknown route(1000 routes)                  | 991 | 0.039429 | +0.038270 | 3302% slower\nFastRoute(cached) - unknown route(1000 routes)          | 990 | 0.040800 | +0.039641 | 3420% slower\nFastRoute(cached) - last route(1000 routes)             | 999 | 0.045065 | +0.043906 | 3788% slower\nFastRoute - last route(1000 routes)                     | 999 | 0.064694 | +0.063535 | 5481% slower\nPux PHP - unknown route(1000 routes)                    | 978 | 0.316016 | +0.314857 | 27163% slower\nsymfony/routing - unknown route(1000 routes)            | 992 | 0.359482 | +0.358323 | 30912% slower\nsymfony/routing - last route(1000 routes)               | 999 | 0.418813 | +0.417654 | 36031% slower\nPux PHP - last route(1000 routes)                       | 999 | 0.440489 | +0.439330 | 37901% slower\nMacaw - unknown route(1000 routes)                      | 991 | 1.687441 | +1.686282 | 145475% slower\nMacaw - last route(1000 routes)                         | 999 | 1.786542 | +1.785383 | 154024% slower\n\n## First route matching\n\nThis benchmark tests how quickly each router can match the first route. 1,000 routes each with 9 arguments.\n\nThis 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.\n\nTest Name | Results | Time | + Interval | Change\n--------- | ------- | ---- | ---------- | ------\nnikic/fast-route - first route(1000)                    | 998 | 0.002929 | +0.001571 | 116% slower\ncorneltek/pux(php) - first route(1000)                  | 996 | 0.002971 | +0.001613 | 119% slower\ninhere/sroute(Router) - first(1000)                     | 979 | 0.006202 | +0.004844 | 357% slower\ninhere/sroute(SRouter) - first(1000)                    | 999 | 0.006627 | +0.005269 | 388% slower\nsymfony/routing(cached) - first route(1000)             | 985 | 0.006858 | +0.005501 | 405% slower\nsymfony/routing - first route(1000)                     | 995 | 0.023105 | +0.021747 | 1601% slower\nnikic/fast-route(cached) - first route(1000)            | 999 | 0.041133 | +0.039775 | 2929% slower\nMacaw - first route (1000 routes)                       | 999 | 1.782017 | +1.780659 | 131128% slower\n\n## 使用说明\n\n\u003e 各个版本的方法名和参数都是一样的\n\n首先, 需要导入类\n\n```php\nuse Inhere\\Route\\Router;\n\n$router = new Router();\n```\n\n### 快速开始\n\n创建一个简单的 `public/index.php` 文件:\n\n```php\nuse Inhere\\Route\\Router;\n\n// 需要先加载 autoload 文件\nrequire dirname(__DIR__) . '/vendor/autoload.php';\n\n$router = new Router();\n\n$router-\u003eget('/', function() {\n    echo 'hello';\n});\n\n// 开始调度运行\n$router-\u003edispatch();\n```\n\n使用php启动一个测试server： `php -S 127.0.0.1:8080 -t ./public`\n\n好了，现在你可以访问 http://127.0.0.1:8080 可以看到输出 `hello`\n\n- 不使用 Composer\n\n如果是直接下载的包代码，可以加载 `test/boot.php` 文件，也可以加载到 `Inhere\\Route` 命名空间.\n\n用如下的语句替换上面的 `autoload.php` 加载语句即可：\n\n```php\nrequire dirname(__DIR__) . '/test/boot.php';\n```\n\n## 添加路由\n\n```php\n// 匹配 GET 请求. 处理器是个闭包 Closure\n$router-\u003eget('/', function() {\n    echo 'hello';\n});\n\n// 匹配参数 'test/john'\n$router-\u003eget('/test/{name}', function($params) {\n    echo $params['name']; // 'john'\n}, [\n      'name' =\u003e '\\w+', // 添加参数匹配限制。若不添加对应的限制，将会自动设置为匹配除了'/'外的任何字符\n]);\n\n// 可选参数支持。匹配  'hello' 'hello/john'\n$router-\u003eget('/hello[/{name}]', function() {\n    echo $params['name'] ?? 'No input'; // 'john'\n}, [\n     'name' =\u003e '\\w+', // 添加参数匹配限制\n]);\n\n// 匹配 POST 请求\n$router-\u003epost('/user/login', function() {\n    var_dump($_POST);\n});\n\n// 匹配 GET 或者 POST\n$router-\u003emap(['get', 'post'], '/user/login', function() {\n    var_dump($_GET, $_POST);\n});\n\n// 允许任何请求方法\n$router-\u003eany('/home', function() {\n    echo 'hello, you request page is /home';\n});\n$router-\u003eany('/404', function() {\n    echo \"Sorry,This page not found.\";\n});\n```\n\n### 使用路由组\n\n```php\n// 路由组\n$router-\u003egroup('/user', function ($router) {\n    $router-\u003eget('/', function () {\n        echo 'hello. you access: /user/';\n    });\n    $router-\u003eget('/index', function () {\n        echo 'hello. you access: /user/index';\n    });\n});\n```\n\n### 使用控制器\n\n```php\n// 使用 控制器\n$router-\u003eget('/', App\\Controllers\\HomeController::class);\n$router-\u003eget('/index', 'App\\Controllers\\HomeController@index');\n```\n\n### 备用路由处理\n\n可以注册一个备用路由处理。当没匹配到时，就会使用它\n\n```php\n$router-\u003eany('*', 'fallback_handler');\n```\n\n\u003e 如果配置了 `'ignoreLastSlash' =\u003e true`, '/index' 等同于 '/index/'\n\n#### 注意\n\n可选参数 - 只能是在路由path的最后\n\n正确的：\n\n```php\n/hello[/{name}]      // match: /hello/tom   /hello\n/my[/{name}[/{age}]] // match: /my/tom/78  /my/tom\n```\n\n错误的：\n\n```php\n/my[/{name}]/{age}\n```\n\n### 自动匹配路由\n\n支持根据请求的URI自动匹配路由(就像 yii 一样), 需配置 `autoRoute`. \n\n```php \n    'autoRoute' =\u003e 1, // 启用\n    'controllerNamespace' =\u003e 'App\\\\Controllers', // 控制器类所在命名空间\n    'controllerSuffix' =\u003e 'Controller', // 控制器类后缀\n```\n\n\u003e 请参看示例 `example` 中的使用\n\n此时请求没有配置路由的 `/demo` `/demo/test`。将会自动尝试从 `App\\\\Controllers` 命名空间下去查找 `DemoController`\n\n查找逻辑是 \n\n- 只有一节的(如`/demo`)，直接定义它为控制器类名进行查找\n- 大于等于两节的默认先认为最后一节是控制器类名，进行查找\n- 若失败，再尝试将倒数第二节认为是控制器名，最后一节是action名\n\n## 设置路由配置\n\n```php\n// set config\n$router-\u003econfig([\n    'ignoreLastSlash' =\u003e true,    \n    'autoRoute' =\u003e 1,\n    'controllerNamespace' =\u003e 'app\\\\controllers',\n    'controllerSuffix' =\u003e 'Controller',\n]);\n```\n\n\u003e NOTICE: 必须在添加路由之前调用 `$router-\u003econfig()` \n\n## 路由匹配\n\n```php \narray public function match($path, $method)\n```\n\n- `$path` string 请求的URI path\n- `$method` string 请求的request method\n- 返回 `array` 返回匹配结果信息\n\n### 示例\n\n根据请求的 URI path 和 请求 METHOD 查找匹配我们定义的路由信息。\n\n```php\n$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);\n$method = $_SERVER['REQUEST_METHOD'];\n\n$routeInfo = $router-\u003ematch($path, $method);\n```\n\n根据返回的路由信息，我们就可以自由的决定如何调用对应的处理。\n\n\u003e 关于返回的数据结构，可以查看 [关键方法参考](docs/classes-api.md)\n\n## 路由调度\n\n如果你不想自己实现路由调度，可以使用内置的路由调度器 `Inhere\\Route\\Dispatcher\\Dispatcher`\n\n```php\nuse Inhere\\Route\\Dispatcher\\Dispatcher;\n\n$dispatcher = new Dispatcher([\n    // default action method name\n    'defaultAction' =\u003e 'index',\n\n    'actionPrefix' =\u003e '',\n\n    'actionSuffix' =\u003e 'Action',\n\n    'dynamicAction' =\u003e true,\n    // @see Router::$globalParams['act']\n    'dynamicActionVar' =\u003e 'act',\n]);\n```\n\n### 设置事件处理\n\n```php\n// 成功匹配路由\n$dispatcher-\u003eon(Dispatcher::ON_FOUND, function ($uri, $cb) use ($app) {\n    $app-\u003elogger-\u003edebug(\"Matched uri path: $uri, setting callback is: \" . is_string($cb) ? $cb : get_class($cb));\n});\n\n// 当匹配失败, 重定向到 '/404'\n$dispatcher-\u003eon('notFound', '/404');\n// 或者, 当匹配失败, 输出消息...\n$dispatcher-\u003eon('notFound', function ($uri) {\n    echo \"the page $uri not found!\";\n});\n```\n\n### 使用控制器方法\n\n通过`@`符号连接控制器类和方法名可以指定执行方法。\n\n```php\n$router-\u003eget('/', App\\Controllers\\HomeController::class);\n\n$router-\u003eget('/index', 'App\\Controllers\\HomeController@index');\n$router-\u003eget('/about', 'App\\Controllers\\HomeController@about');\n```\n\n\u003e NOTICE: 若第二个参数仅仅是个 类，将会尝试执行通过 `defaultAction` 配置的默认方法\n\n### 动态匹配控制器方法\n\n动态匹配控制器方法, 需配置 \n\n```php\n'dynamicAction' =\u003e true,  // 启用\n// action 方法名匹配参数名称，符合条件的才会当做action名称\n// @see Router::$globalParams['act'] 匹配 '[a-zA-Z][\\w-]+'\n'dynamicActionVar' =\u003e 'act',\n```\n\n\u003e NOTICE: 使用动态匹配控制器方法, 应当使用 `any()` 添加路由. 即此时不能限定请求方法 `REQUEST_METHOD`\n\n```php\n// 访问 '/home/test' 将会执行 'App\\Controllers\\HomeController::test()'\n$router-\u003eany('/home/{act}', App\\Controllers\\HomeController::class);\n\n// 可匹配 '/home', '/home/test' 等\n$router-\u003eany('/home[/{act}]', App\\Controllers\\HomeController::class);\n```\n\n\u003e NOTICE: 上面两个的区别是 第一个无法匹配 `/home`\n\n### 使用方法执行器\n\n配置 `actionExecutor` 为你需要的方法名，例如配置为 `'actionExecutor' =\u003e 'run'`，那所有的方法请求都会提交给此方法。\n会将真实的 action 作为参数传入`run($action)`, 需要你在此方法中调度来执行真正的请求方法。\n\n\u003e NOTICE: 在你需要将路由器整合到自己的框架时很有用\n\n示例：\n\n```php\n// 访问 '/user', 将会调用 App\\Controllers\\UserController::run('')\n$router-\u003eget('/user', 'App\\Controllers\\UserController');\n\n// 访问 '/user/profile', 将会调用 App\\Controllers\\UserController::run('profile')\n$router-\u003eget('/user/profile', 'App\\Controllers\\UserController');\n\n// 同时配置 'actionExecutor' =\u003e 'run' 和 'dynamicAction' =\u003e true,\n// 访问 '/user', 将会调用 App\\Controllers\\UserController::run('')\n// 访问 '/user/profile', 将会调用 App\\Controllers\\UserController::run('profile')\n$router-\u003eany('/user[/{name}]', 'App\\Controllers\\UserController');\n```\n\n## 开始路由匹配和调度\n\n```php\n$router-\u003edispatch($dispatcher);\n```\n\n## 运行示例\n\n示例代码在 `example` 下。\n\n- 对象版本\n\n你可以通过 `php -S 127.0.0.1:5670 example/object.php` 来运行一个测试服务器, 现在你可以访问 http://127.0.0.1:5671\n\n## 测试 \n\n```bash\nphpunit\n```\n\n- simple benchmark\n\n```bash\nphp example/benchmark.php\n```\n\n## License \n\nMIT\n\n## 我的其他项目\n\n### `inhere/console` [github](https://github.com/inhere/php-console) [git@osc](https://git.oschina.net/inhere/php-console)\n\n功能丰富的命令行应用，命令行工具库\n\n### `inhere/php-validate` [github](https://github.com/inhere/php-validate)  [git@osc](https://git.oschina.net/inhere/php-validate)\n \n 一个简洁小巧且功能完善的php验证库。仅有几个文件，无依赖。\n \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finhere%2Fphp-sroute","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finhere%2Fphp-sroute","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finhere%2Fphp-sroute/lists"}