这是将 URI 与 PHP 中用于 MVC 的类/方法匹配的好方法吗 [英] Is this a good way to match URI to class/method in PHP for MVC

查看:16
本文介绍了这是将 URI 与 PHP 中用于 MVC 的类/方法匹配的好方法吗的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 MVC 的新手,所以这是我的第一次尝试,我相信你们可以在这方面给我改进,感谢您提供任何提示或帮助!

I am new to MVC so this is my first attempt and I am sure you guys can give me improvement on this, thanks for any tips or help!

以下是我为我的个人框架设计的路由器/调度程序系统,这是我第一次尝试使用 MVC 模式.

Below is what I have come up with for a router/dispatcher system for my personal framework I am working on, it is my first attempt at using the MVC pattern.

第一块代码只是我的 .htaccess 文件,它通过我的 index.php 文件路由所有请求.

The first block of code is just my .htaccess file which routes all request through my index.php file.

第二个代码块是我的Routes"数组,它会告诉 Router 对象,调用哪个类和方法,以及任何 ID 或分页号码(如果存在).

The second block of code is my array of "Routes" which will tell the Router object, which class and method to call as well as any ID or paging numbers if they exists.

第三块代码是路由器类.

Third block of code is the router class.

第四块只是运行类

因此,路由器类必须使用正则表达式将 URI 与路由映射中的路由匹配,理论上,当正则表达式必须运行在 50 多个路由的列表中时,这听起来性能很差,应该我的做法不一样?我使用正则表达式的主要原因是匹配路由中存在的页码和 ID 号.

So the router class has to use regex to match the URI with a route in the route map, in theory, this just sounds like bad performance when there is a list of 50+ routes that the regex has to run on, should I be doing this differently? The main reason I use the regex is to match page numbers and ID numbers when they exists in the route.

另外请不要只是告诉我使用一个框架,我这样做是为了更好地学习它,我通过这种方式学习得更好,现在只是不想使用现有框架,我已经研究了所有主要框架,并且一些不太常见的想法已经.

Also please do not just tell me to use a framework, I am doing this to learn it better, I learn better this way and just prefer to not use an existing framework at this time, I have studies all the main ones and some less common ones for ideas already.

1) 那么主要问题是,有什么地方看起来不对吗?

1) So the main question, does anything just not look right?

2) 有没有比像我这样在数组上使用正则表达式更好的方法来检测 URI 中的内容,在高流量站点上考虑一下?

2) Is there a better way to detect what is in the URI than using the regex on an array like I am doing, consider it on a high traffic site?

3) 由于所有内容都通过 index.php 文件路由,我将如何处理 AJAX 请求?

3) Since everything is routed through the index.php file with this, how would I go about handling AJAX requests?

对不起,如果这令人困惑,我自己有点困惑!

Sorry if this is confusing, I am a little confused mtyself!

.htaccess 文件

.htaccess file

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$   index.php?uri=$1    [NC,L,QSA]

映射数组()

/**
 * Map URI to class/method and ID and Page numbers
 * Must be an array
 */
$uri_route_map = array( 
    //forums
    'forums/' => array(
        'controller' => 'forums',
        'method' => 'index',
        'id_number' => '',
        'page_number' => ''),

    'forums/viewforum/(?<id_number>d+)' =>  array(
        'controller' => 'forums',
        'method' => 'viewforum',
        'id_number' => isset($id_number),
        'page_number' => ''),  

    'forums/viewthread/(?<id_number>d+)' =>  array(
        'controller' => 'forums',
        'method' => 'viewthread',
        'id_number' => isset($id_number),
        'page_number' => ''),

    'forums/viewthread/(?<id_number>d+)/page-(?<page_number>d+)' =>  array(
        'controller' => 'forums',
        'method' => 'viewthread',
        'id_number' => isset($id_number),
        'page_number' => isset($page_number)),

    // user routes
    // account routes
    // blog routes 
    // mail routes
    // various other routes
);

读取并匹配上面Map数组的Router类

Router class that reads and matches the Map array above

/**
 * Run URI against our Map array to get class/method/id-page numbers
 */
 class Router
{
    private $_controller = '';
    private $_method = '';
    public $page_number = '';
    public $id_number = '';

    public function __construct($uri, array $uri_route_map)
    {
        foreach ($uri_route_map as $rUri => $rRoute)
        {
            if (preg_match("#^{$rUri}$#Ui", $uri, $uri_digits))
            {
                //if page number and ID number in uri then set it locally
                $this->page_number = (isset($uri_digits['page_number']) ? $uri_digits['page_number'] : null);
                $this->id_number = (isset($uri_digits['id_number']) ? $uri_digits['id_number'] : null);
                $this->_controller = $rRoute['controller'];
                $this->_method = $rRoute['method'];

                // just for debug and testing while working on it / will be removed from final code
                echo '<hr> $page_number = ' . $this->page_number . '<br><br>';
                echo '<hr> $id_number = ' . $this->id_number . '<br><br>';
                echo '<hr> $controller = ' . $this->_controller . '<br><br>';
                echo '<hr> $method = ' . $this->_method . '<br><br>';
                break;
            }else{
                $this->page_number = '';
                $this->id_number = '';
                $this->_controller = '404';
                $this->_method = '404';
            }
        }
    }

    public function getController()
    {
        return $this->_controller;
    }

    public function getMethod()
    {
        return $this->_method;
    }

    public function getPageNumber()
    {
        return $this->page_number;
    }

    public function getIDNumber()
    {
        return $this->id_number;
    }

    /**
     * Call our class and method from values in the URI
     */
    public function dispatch()
    {
        if (file_exists('controller' . $this->_controller . '.php'))
        {
            include ('controller' . $this->_controller . '.php');
            $controllerName = 'Controller' . $this->_controller;
            $controller = new $controllerName($this->getIDNumber(),$this->getPageNumber());
            $method = $this->_method;
            if (method_exists($this->_controller, $this->_method))
            {
                return $controller->$method();
            } else {
                // method does not exist
            }
        } else {
            // Controller does not exist
        }
    }

}

运行它

/**
 * Testing the class
 */
$uri = isset($_GET['uri']) ? $_GET['uri'] : null;
$router = new Router($uri, $uri_route_map);
$router->dispatch();

?>

推荐答案

1) 我觉得没问题.不过代码看起来有点乱.

1) Look alright to me. The code looks a bit messy though.

2) 是的,有更好的方法.您正在执行正则表达式,因为您想匹配您不知道的 URL 部分.为什么不做 $parts = purge("/", $uri) 然后看看你是否能找到你要找的页面?您需要定义每个页面需要多少个参数,否则您将不知道是选择带有参数 array("viewform", 123) 还是 forums>forums/viewforum 带参数 array(123).

2) Yes there is a better way. You're doing the regex because you want to match parts of the URL that you don't know. Why not do $parts = explode("/", $uri) then see if you can find the page you're looking for? You will need to define how many parameters you're expecting for each page or you wont know whether to pick forums with parameters array("viewform", 123) or forums/viewforum with parameters array(123).

explode 感觉比正则表达式更好加载.它还增加了改进错误处理的好处.如果传递给 viewforum 的参数不是数字怎么办?当然你可以比 "404" 做得更好;)

explode feels loads better than a regex. It also adds the benefit of improved error handling. What if the argument passed to viewforum is not a number? Surely you can do better than "404" ;)

3) 制作一个单独的 ajax 处理程序.无论如何,Ajax 都是隐藏的,因此您无需费心提供语义 URL.

3) Make a seperate ajax handler. Ajax is hidden from view anyway so you don't need to bother with providing semantic URLs.

示例:

function find_route($parts) {
    foreach ($uri_route_map as $route => $route_data) {
        $route_check = implode("/", array_slice($parts, 0, count($parts) - $route_data['num_arguments']));
        if ($route_check === $route) {
            return $route_data;
        }
    }
    throw new Exception("404?");
}

$uri = "forum/viewforum/522";

$parts = explode("/", $uri);
$route = find_route($parts);
$arguments = array_slice($parts, count($parts) - $route['num_arguments']);

$controller = $rRoute['controller'];
$method = $rRoute['method'];
$controller_instance = new $controller();
call_user_func_array(array($controller_instance, $method), $arguments);

(未经测试)

插件

由于 $uri_route_map,您无​​法动态"注册更多插件或页面或路由".我会添加一个函数来动态地向 Router 添加更多路由.

Because of $uri_route_map you can't 'dynamically' register more plugins or pages or 'routes'. I'd add a function to add more routes dynamically to the Router.

此外,您可以考虑一些自动发现方案,例如,将检查文件夹 plugins/ 中包含名为manifest.php"的文件的文件夹,当调用该文件时,可以选择添加更多路由到路由器.

Additionally you could consider some auto-discovery scheme that, for instance, will check the folder plugins/ for folders with a file called "manifest.php" that, when called, will optionally add more routes to Router.

这篇关于这是将 URI 与 PHP 中用于 MVC 的类/方法匹配的好方法吗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆