我有一个我为路由组件here is the full code编写的代码,它基本上构建了许多小的(特定于路由的)规则中的任意数量的大型正则表达式(取决于配置值)验证给定请求是否可以由注册路由映射。
一般过程包括首先装饰每条路线,以便使用占位符的路线如
/path/to/:variable_name
变成像这样的正则表达式:
/path/to/(?P<R1V1>[^/]+)
在验证时,这条路线会在每批任意大小的单个正则表达式中粘合在一起。
对于'正常'用法,例如,有1-4个占位符的500条路线,它的效果非常好。但是在对它进行基准测试时,我注意到对于极大数量的占位符 AND 和极大量的路径(目前有11个占位符和50000个路由),我找不到最后一个注册路径的代码。< / p>
我无法弄明白为什么。据我所知,事情应该大致以相同的方式表现,采取(可能?我的O符号生锈)每个数量级的O(n * m)次(n是批量,m是多少)正则表达式是批量存在的)。
也许这是我正在测试的方式?如果不是,请你指点我正在做的任何有问题的事情?
如果有任何用处,我使用的基准测试就是这里的基准
<?php
require dirname(__FILE__).'/../vendor/autoload.php';
$router = new \CFV\Router();
$dispatcher = new \CFV\Dispatcher();
$dispatcher::$ROUTES_PER_LOT = 20;
// $dispatcher::$THROW_ON_FAIL = true;
$callback = function (){};
$num_args = 11;
$routes_amount = 50000;
$matches_amount = 1;
$args = implode('/', array_map(function($i){ return ':arg' . $i; }, range(1, $num_args)));
$params = implode('/', array_map(function($i){ return '_arg' . $i; }, range(1, $num_args)));
$last_tried = '';
$load_start = microtime(true);
for ($i = 0, $str = 'a'; $i < $routes_amount; $i++, $str++) {
$router->connect("/$str/$args", $callback);
$last_tried = "/$str/$params";
}
printf("Took: %fs to load all\n", microtime(true) - $load_start);
$dispatcher->setRouter($router);
$search_start = microtime(true);
$found = $dispatcher->dispatch($last_tried);
printf("Took: %fs searching all\n", microtime(true) - $search_start);
任何指针都会很棒。
答案 0 :(得分:2)
有些限制。来自the manual:
主题字符串的最大长度是最大的正数 整数变量可以容纳。但是,PCRE使用递归 处理子模式和无限重复。这意味着 可用的堆栈空间可能会限制主题字符串的大小 由某些模式处理。
此外,还有PCRE recursion limit和backtrack limit
如果模式中有超过15个捕获括号,则PCRE具有 在递归过程中获得额外的内存来存储数据 通过使用pcre_malloc,之后通过pcre_free释放它。如果不 可以获得内存,它为前15次捕获保存数据 仅括号,因为没有办法给出内存不足的错误 从递归中。
价:
http://php.net/manual/en/regexp.reference.recursive.php
http://php.net/pcre.configuration#ini.pcre.recursion-limit
http://php.net/pcre.configuration#ini.pcre.backtrack-limit