如何用PHP制作路由器?

6

我目前正在为我的一个项目开发路由器,需要执行以下操作:

例如,假设我们有以下一组设置路由:

$routes = [
    'blog/posts' => 'Path/To/Module/Blog@posts',
    'blog/view/{params} => 'Path/To/Module/Blog@view',
    'api/blog/create/{params}' => 'Path/To/Module/API/Blog@create'
];

然后,如果我们通过以下URL传递:http://localhost/blog/posts,它将分派blog/posts路由 - 这很好。

现在,当涉及到需要参数的路由时,我只需要一种实现通过传递参数的方法(即http://localhost/blog/posts/param1/param2/param3),以及在前面添加api来创建http://localhost/api/blog/create/以定位API调用的能力,但我被卡住了。


2
敢问您是否考虑选择现有的路由器? - Progrock
@Progrock 如果有类似于我需要的功能的现有路由器,我很乐意以此为基础构建,但如果可能的话,我更倾向于建立一个完全符合我的标准的路由器。 - Hypernami
不清楚你想要路由器做什么,是指重定向吗?这是在服务器上完成的(如apache、nginx等),或者您可以使用slug作为主键,任何路由器作为值,并将其保存在memcache中。稍后只需按当前URL查询并重定向即可。 - peixotorms
路由是一个非常通用的任务 - 你可能有哪些标准是没有在 Symfony 路由中实现的呢?(作为单独的包可用 http://symfony.com/doc/current/book/routing.html) - Denis Mysenko
2
我希望我们可以跳过通常的“为什么不使用现有的”回答,这有点多余。很可能每个人都知道已经存在路由器。有时候人们只是想自己制作,为了学习或者只是因为喜欢,谁在乎呢。这种回答只会让人感到居高临下。 - Omar Gonzalez
2个回答

6

以下是一些基础知识,目前路由系统可以设置模式匹配,如果应用程序路径以该模式开头,则匹配成功。路径的其余部分将转换为参数。

<?php
class Route
{
    public $name;
    public $pattern;
    public $class;
    public $method;
    public $params;
}

class Router
{
    public $routes;

    public function __construct(array $routes)
    {
        $this->routes = $routes;
    }

    public function resolve($app_path)
    {
        $matched = false;
        foreach($this->routes as $route) {
            if(strpos($app_path, $route->pattern) === 0) {
                $matched = true;
                break;
            }
        }

        if(! $matched) throw new Exception('Could not match route.');

        $param_str = str_replace($route->pattern, '', $app_path);
        $params = explode('/', trim($param_str, '/'));
        $params = array_filter($params);

        $match = clone($route);
        $match->params = $params;

        return $match;
    }
}

class Controller
{
    public function action()
    {
        var_dump(func_get_args());
    }
}

$route = new Route;
$route->name    = 'blog-posts';
$route->pattern = '/blog/posts/';
$route->class   = 'Controller';
$route->method  = 'action';

$router = new Router(array($route));
$match  = $router->resolve('/blog/posts/foo/bar');

// Dispatch
if($match) {
    call_user_func_array(array(new $match->class, $match->method), $match->params);
}

输出:

array (size=2)
  0 => string 'foo' (length=3)
  1 => string 'bar' (length=3)

0
这是一个基本版本 - 只是一个概念版本,用于展示功能,我不建议在生产环境中使用它。
$routes = [
    'blog/view' => 'Example@index',
    'api/forum/create' => 'other.php'
];

$url = explode('/', $_GET['url']);

if (isset($url[0]))
{
    if ($url[0] == 'api')
    {
        $params = array_slice($url, 3);
        $url = array_slice($url, 0, 3);
    }
    else
    {
        $params = array_slice($url, 2);
        $url = array_slice($url, 0, 2);
    }
}

$url = implode('/', $url);

if (array_key_exists($url, $routes))
{
    $path = explode('/', $routes[$url]);
    unset($path[count($path)]);
    $segments = end($path);
    $segments = explode('@', $segments);

    $controller = $segments[0];
    $method = $segments[1];

    require_once APP_ROOT . '/app/' . $controller . '.php';
    $controller = new $controller;

    call_user_func_array([$controller, $method], $params);  
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接