grithin / phproute
PHP Web 路由器。
Requires
- php: >=5.5.9
- grithin/phpbase: >=3.0.0
This package is not auto-updated.
Last update: 2024-09-14 18:31:30 UTC
README
最初,Apache 将文件系统路径映射到传入请求的 URL 路径。这对于脚本来说并不理想,因为 Apache 可能会失败并返回纯文本脚本。将文件系统与 URL 路径匹配仍然是出乎意料的途径。
此 Route 类提供了文件路径到 URL 路径映射的功能,而不使脚本文件公开,并且增加了一些功能
- 一个
_routing.php
文件可以像.htaccess
文件一样使用mod_rewrite
。- 循环规则检查。当路径由于路由规则而更改时,可能会希望重新检查现有规则以匹配新路径,并进行后续重写。这是通过
Route
实现的。
- 循环规则检查。当路径由于路由规则而更改时,可能会希望重新检查现有规则以匹配新路径,并进行后续重写。这是通过
- 一个
_control.php
文件将在其放置的路径层次结构内的任何内容上运行。
这种方式的好处,而不是使用直接映射到平面控制器类的单个路由文件,是
- 可预期的控制逻辑位置
/section/page
默认在/section/page.php
- 特定路径的路由规则的可预期位置
- 如果一个部分有特定的路由,它们将位于
/section/_routing.php
或/_routing.php
- 如果一个部分有特定的路由,它们将位于
- 特定部分控制逻辑的可预期位置
- 例如,如果只有特定类型的用户可以访问部分,那么逻辑将在
section/_control.php
- 例如,如果只有特定类型的用户可以访问部分,那么逻辑将在
- 复杂路由:请参阅路由循环
这种路由方法有一些缺点
- 为了获取所有路由规则,必须收集各种
_routing.php
文件 - 控制逻辑作为文件而不是函数运行。尽管 Route 将文件的上下文隔离开来,以避免变量冲突,但使用文件的方式改变了测试的编写方式
- 为了获取所有可能的路由,必须考虑路由规则和将 URL 路径匹配到文件路径的默认行为
让我们考虑一些框架 X 中的 UserController,该框架使用平面路由。对于 UserController,它处理类似 '/user/x' 的传入路径的能力是共享功能和变量的能力。有时,一组控制函数可以访问相同的控制相关实用函数是有用的,有时,部分控制器设置一些初始化或部分特定变量数据是有用的。但是,所有这些都可以通过 Route
通过部分 _control.php
文件和 Route
全局变量(请参阅路由全局变量)来实现
简单示例
文件路径
public/index.php
control/page.php
# public/index.php $_SERVER['REQUEST_URI'] = '/page'; $Route = new Route(['folder'=>realpath(__DIR__.'/../control')]); $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $Route->handle($path); # loads control/page.php
结构
有一个控制文件夹(/control
),在该控制文件夹中有路由文件和控制文件。
路由文件根据 URL 路径逐步加载。如果 URL 为 http://bobery.com/part1/part2/part3
,则路由器会尝试加载
/control/_routing.php
/control/part1/_routing.php
/control/part1/part2/_routing.php
/control/part1/part2/part3/_routing.php
并非所有这些路由文件都需要存在。而且,在任何时候,路由文件都可以更改路由令牌,从而导致加载不同的路由文件系列。
路由文件的结果要么是最终路径,要么是回调。
如果路由文件没有做任何事情,最终路径将保持为 URL 路径。
控制文件以与路由文件相同的方式加载,并根据最终路径加载。如果最终路径是 /part1/part2/part3
,则路由器会尝试加载
/control/_control.php
/control/part1/_control.php
/control/part1/part2/_control.php
/control/part1/part2/part3/_control.php
并非所有这些控制文件都需要存在。在路径中的任何位置,您都可以使用令牌名称而不是 _control.php
,它将具有优先级。因此,它可以是
/control/_control.php
/control/part1.php
/control/part1/part2.php
/control/part1/part2/part3.php
在这里,/control/part1.php
替换了 /control/part1/_control.php
。/control/_control.php
是一个可选的全局控制文件,它为所有请求加载。
路由全局变量
在链式控制逻辑的过程中,链中的项目有时需要共享功能或变量。为了启用此功能,Route
提供了一个全局数组,它将其注入/解包到控制文件(如 _control.php
或 page.php
)中。默认情况下,始终有两个全局变量可用:Route
,它指的是路由实例,以及 control
,它是一个 ArrayObject,您可以将控制功能和您想共享的变量放置在其中。然而,您可以添加全局变量。
# file: _control.php $control['sale'] = '10% off all blah'; $Route->globals['customize_for_user'] = function(){}; # file: section/item.php view($customize_for_user($control['sale']))
路由循环
路由文件只运行一次,但如果路径改变,它的规则可能被多次应用。这与 mod_rewrite 的规则循环操作类似。它还像 mod_rewrite 一样,允许规则具有最终标志,并停止循环。
路径:/test1/test2/test3
路由加载
- 加载
/_routing.php
- 运行来自
/_routing.php
的规则 - 没有路径改变,继续
- 加载
/test1/_routing.php
- 运行来自
/test1/_routing.php
的规则 - 没有路径改变,继续
- 加载
/test1/test2/_routing.php
- 运行来自
/test1/test2/_routing.php
的规则 - 路径变为
/moved_section1/bob
- 运行来自
/_routing.php
的规则 - 路径变为
/section1/bob
- 运行来自
/_routing.php
的规则 - 没有路径改变,继续
- 加载
/section1/_routing.php
- 运行来自
/section1/_routing.php
的规则 - 没有路径改变,继续
- 路径最终结果:
/section1/bob
停止循环
规则可以有一个 last
标志,如果该规则匹配,循环将在其之后停止。
您还可以在路由文件或路由规则回调中调用 $route->routing_end()
。
调试
只需检查 $route 实例
try{ $route->handle('http://test.com/not/a/real/path'); }catch(RouteException $e){ \Grithin\Debug::quit($route); }
路由文件
路由文件包含 $route
,包含路由实例。
路由文件应返回一个路由规则数组。
return [ ['bob','bill'], ['bill','sue'] ];
路由规则
[$match_pattern, $change, $flags]
$match_pattern
默认情况下,将 match_pattern 解释为精确、区分大小写的匹配模式。对于 http://bobery.com/part1/part2/part3
,part1/part2/part3
将匹配,但 part1/part2
和 part1/part2/part3/
则不会。
标志可以更改 match_pattern 的解释。
regex
作为正则表达式caseless
对小写主题进行匹配
正则表达式
默认数字组匹配
# reposition id ['/item/([0-9]+)/view', '/item/view/[1]', 'regex']
命名匹配
# match anything and name it "path" ['(?<path>.*)', 'prefix/[path]', 'regex'] # match numbers and name it "id" ['old/(?<id>[0-9]+)', 'new/[id]','regex']
- 最后一个匹配项也存储在
$route->regex_last_match
中 - 匹配项的汇总存储在
$route->regex_matches
中 - 这两个都将有键值,既有数字索引,也有命名组(如果存在命名组)
- 例如
$Route->regex_matches['id']
- 例如
使用匹配项
除了匹配回调(请参阅 $change > callable)之外,控制文件还可以访问路由实例。并且,在规则 ['test/from/(?<id>[0-9]+)','/test/to/[id]', 'regex,last']
中,我们有
route.tokens = [ "test", "to", "123"] route.regexMatch = { "0": "test\/from\/123", "id": "123", "1": "123"}
$change
可以是字符串或可调用对象
字符串
没有 regex
标志,将替换整个路径。
有 regex
标志,用作专门的匹配替换(类似于 preg_replace 替换参数)。为了方便起见,可以使用匹配组
'['matchName']'
示例
$rules[] = ['user/(?<id>[0-9]+)','usr/[id]','regex'];
可调用对象
一个符合 Route::is_callable 的可调用对象 function($route, $rule)
,它应返回一个新的路径。
如果存在 regex
标志,可调用对象作为 preg_replace_callback
回调,其中第三个参数开始是正常的 preg_replace_callback
回调参数(function($route, $rule, $matches)
)
$flags
逗号分隔的标志,或标志数组
-
'once' 规则只应用一次,其余时间忽略
-
在文件中匹配到最后一条规则 'file:last'。路由器将不再解析包含文件中的更多规则,但会解析后续文件中的规则。
-
'last' 是最后匹配的规则。路由器将在此之后停止解析规则。
-
'301' 将发送 http 重定向代码 301(永久重定向)。
-
'307' 将发送 http 重定向代码 307(临时重定向)。
-
'303' 将发送 http 重定向代码 303(告诉客户端以 GET 请求重新发出)。
-
'params' 保持 GET 参数:将在 http 重定向的末尾附加查询字符串。
-
'caseless': 忽略大小写。
-
'regex': 应用正则表达式模式匹配。
有用示例
将文件夹指向索引控制文件。
return [ ['^$','index','regex,last'], # the root path, special in that the initial `/` is removed and the path is empty ['^(?<path>.*)/$','[path]/index','regex,last'], # paths ending in `/` to be pointed to their corresponding index control files ]
id 的重新分配
- 在
_routing.php
中
['test/from/(?<id>[0-9]+)','/test/to/[id]', 'regex,last'],
- 这也提供了
$Route->named_matches['id']
控制
已加载的控制文件将 $route 实例注入到它们的上下文中,以及通过 $route->globals
数组键入的其他任何内容。
如果您想在标记完成之前结束路由,您必须退出或调用 $route->control_end()
。如果没有对应控制文件的剩余标记,路由器将考虑这是一个未找到页面的事件。
注意
Route 期望至少有一个文件,不包括主 _control.php
文件。如果某些路由将以主 _control.php
结尾,您必须退出或捕获并处理 RouteException。