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

查看:63
本文介绍了这是将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.

第二个代码块是我的路由"数组,它将告诉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]

地图array()

/**
 * 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 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 = explode("/", $uri),然后查看是否可以找到您要查找的页面?您将需要定义每个页面需要多少个参数,否则您将不知道是选择参数array("viewform", 123)forums还是参数array(123)forums/viewforum.

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天全站免登陆