php – 如何使用基于Regex的路由处理404?

请考虑以下非常基本的“控制器”(为简单起见,在这种情况下的功能):

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();

干杯!

点赞