我面临的情况是我不知道如何实现一个功能, 我不确定什么是最好和更快的解决方案。
我有一个简单的路由对象,非常基本,我不需要这个特定项目的高级功能......它存储了一系列路由,唯一允许的方法是GET和POST,这大致是类结构:
class Router
{
// Array of Route Objects
private static $binded_routes = array();
// Method used to register a GET route.
public static function get() {}
// Method used to register a POST route.
public static function post() {}
// Other methods here like redirect(), routeTo(), dispatch()
}
路由可以声明为:
Router::get('index', 'IndexController@method');
Router::get('users/{id}', 'UserController@showUser');
Router::get('route/to/something', 'Controller@method');
Router::get('route/to/something/{param1}', 'Controller@method1');
Router::get('route/to/something/{param1}/{param2}', 'Controller@method2');
存储GET路由的策略是:
路线对象是这样的:
class Route
{
private $route_type = 'GET';
private $route_name = null;
private $route_uri = null;
private $route_params = array();
private $route_controller = null;
private $route_method = null;
// Functions to correctly store and retrieve the above values
}
所以现在我在匹配GET请求方面遇到了麻烦,基于我可以做的事情 那样:
目前,如果没有多个foreach循环,我无法想到管理此过程的方法。 对此最好的方法是什么?有没有办法构建正则表达式?以及如何生成它?
任何帮助都将受到高度赞赏,如果您需要更多信息,请告诉我。
答案 0 :(得分:2)
经过一些编码后,我设法创建了一个工作函数,棘手的部分是将GET请求与params匹配。
例如,如果我有这些路线:
Router::get('user/{id}', 'UserController@showUser');
Router::get('route/path/{param1}', 'SomeController@someMethodA');
Router::get('route/path/{param1}/{param2}', 'SomeController@someMethodB');
用户可以通过浏览器发出如下请求:
site.com/user/10
site.com/route/path/10
site.com/route/path/10/20
知道这一点,我的脚本必须通过以下方式识别(遵循如何解析GET请求的策略)所请求的URI:
route1: user
params: array(10)
route2: route/path
params: array(10)
route3: route/path
params: array(10,20)
以下是代码的相关部分:
$index = 0;
$array_of_matches = array();
// $current_uri is urldecoded route path
$splitted_uri = explode('/', $current_uri);
foreach (self::$binded_routes as $route)
{
if ($route->getURI() === $current_uri && !$route->hasParams())
{
// Gotcha.
$found_route = true;
$route_index = $index;
// No need to continue wasting time...
break;
}
$number_of_matches = 0;
$route_uri_split = explode('/', $route->getURI());
if ($splitted_uri[0] == $route_uri_split[0] && $route->hasParams())
{
$number_of_matches++;
// I need this to eliminate routes like
// users/list when searching for users/{1}
if (count($route_uri_split) > count($splitted_uri))
{
$number_of_matches = 0;
}
for($i = 1; $i < count($splitted_uri); $i++)
{
if (isset($route_uri_split[$i]))
{
if ($route_uri_split[$i] === $splitted_uri[$i])
$number_of_matches++;
else
$number_of_matches--;
}
}
$array_of_matches[$index] = $number_of_matches;
}
// Incrementing index for next array entry.
$index ++;
}
// Now try to find the route with the same amount of params if I still don't have a match.
if (!$found_route)
{
$highest_matches = array_keys($array_of_matches, max($array_of_matches));
foreach ($highest_matches as $match)
{
$matched_route = self::$binded_routes[$match];
$params_portion = ltrim(str_replace($matched_route->getURI(), '', $current_uri), '/');
// If $params_portion is empty it means that no params are passed.
$params_count = (empty($params_portion)) ? 0 : count(explode('/', $params_portion));
if ($params_count == $matched_route->paramsCount())
{
$found_route = true;
$route_index = $match;
$route_params = explode('/', $params_portion);
break;
}
}
}
if ($found_route)
{
// If params are needed set them now.
if (isset($route_params))
self::$binded_routes[$route_index]->setParams($route_params);
// Dispatch the route.
self::$binded_routes[$route_index]->dispatch();
}
else
{
// Route not found... redirect to 404 or error.
}
现在,我知道它看起来很丑陋,我想在可能的情况下改进这个代码。 除了将代码提取到自己的类上下文,委托并使其更“甜蜜”,也许它可以更快,更高效或更聪明。
如果您有任何想法,请告诉我。