请考虑以下非常基本的“控制器”(为简单起见,在这种情况下的功能):
function Index() {
var_dump(__FUNCTION__); // show the "Index" page
}
function Send($n) {
var_dump(__FUNCTION__, func_get_args()); // placeholder controller
}
function Receive($n) {
var_dump(__FUNCTION__, func_get_args()); // placeholder controller
}
function Not_Found() {
var_dump(__FUNCTION__); // show a "404 - Not Found" page
}
以下是基于正则表达式的Route()函数:
function Route($route, $function = null)
{
$result = rtrim(preg_replace('~/+~', '/', substr($_SERVER['PHP_SELF'], strlen($_SERVER['SCRIPT_NAME']))), '/');
if (preg_match('~' . rtrim(str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $route), '/') . '$~i', $result, $matches) > 0)
{
exit(call_user_func_array($function, array_slice($matches, 1)));
}
return false;
}
现在我想将以下URL(忽略尾部斜杠)映射到相应的“控制器”:
/index.php -> Index()
/index.php/send/:NUM -> Send()
/index.php/receive/:NUM -> Receive()
/index.php/NON_EXISTENT -> Not_Found()
这是事情开始变得棘手的部分,我有两个问题我无法解决……我想我不是第一个遇到这个问题的人,所以有人应该有解决方案.
捕获404(已解决!)
我找不到区分对root(index.php)的请求和不存在的请求(index.php / notHere)的方法.我最终为URL提供默认的index.php路由,否则应该提供给404 – Not Found错误页面.我怎么解决这个问题?
编辑 – 解决方案刚刚闪现在我的脑海中:
Route('/send/(:num)', 'Send');
Route('/receive/(:num)', 'Receive');
Route('/:any', 'Not_Found'); // use :any here, see the problem bellow
Route('/', 'Index');
路线的订购
如果我以“逻辑”顺序设置路由,如下所示:
Route('/', 'Index');
Route('/send/(:num)', 'Send');
Route('/receive/(:num)', 'Receive');
Route(':any', 'Not_Found');
所有URL请求都由Index()控制器捕获,因为空的正则表达式(记住:忽略尾随斜杠)匹配所有内容.但是,如果我以“hacky”顺序定义路由,如下所示:
Route('/send/(:num)', 'Send');
Route('/receive/(:num)', 'Receive');
Route('/:any', 'Not_Found');
Route('/', 'Index');
一切似乎都应该像它应该的那样工作.有没有一种优雅的方法来解决这个问题?
路线可能并不总是硬编码(从数据库或其他东西中提取),我需要确保它不会因为定义它们的顺序而忽略任何路由.任何帮助表示赞赏!
解决方法:
好吧,我知道有一种方法可以给猫皮肤,但为什么你会这样做呢?看起来像某些RoR方法可以使用mod_rewrite轻松处理
话虽这么说,我重写了你的路线功能,并且能够实现你的目标.请记住,我添加了另一个条件来直接捕获索引,因为你正在删除所有的/这就是为什么它匹配索引时你希望它匹配404.我还整合了4个Route()调用使用一个foreach().
function Route()
{
$result = rtrim(preg_replace('~/+~', '/', substr($_SERVER['PHP_SELF'], strlen($_SERVER['SCRIPT_NAME']))), '/');
$matches = array();
$routes = array(
'Send' => '/send/(:num)',
'Receive' => '/receive/(:num)',
'Index' => '/',
'Not_Found' => null
);
foreach ($routes as $function => $route)
{
if (($route == '/' && $result == '')
|| (preg_match('~' . rtrim(str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $route)) . '$~i', $result, $matches) > 0))
{
exit(call_user_func_array($function, array_slice($matches, 1)));
}
}
return false;
}
Route();
干杯!