在PHP mvc中路由URL的最有效方法是什么?

在PHP mvc中路由URL的最有效方法是什么?,php,model-view-controller,oop,.htaccess,Php,Model View Controller,Oop,.htaccess,我正在开发一个简单的php mvc,它可以做最简单的事情,但也可以按我需要的方式工作,这是我第一次使用mvc方法而不是Procedural,所以我边学边用 在开发过程中,我意外地以一种奇怪的方式创建了它,目前主.htaccess包含了几乎所有的物理重写,例如论坛: RewriteRule ^forum/([a-zA-Z0-9_]+)_([0-9]+)/$ index.php?controller=forum&method=showThread&

我正在开发一个简单的php mvc,它可以做最简单的事情,但也可以按我需要的方式工作,这是我第一次使用mvc方法而不是Procedural,所以我边学边用

在开发过程中,我意外地以一种奇怪的方式创建了它,目前主
.htaccess
包含了几乎所有的物理重写,例如论坛:

RewriteRule ^forum/([a-zA-Z0-9_]+)_([0-9]+)/$                    index.php?controller=forum&method=showThread&urlTitle=$1&threadId=$2 [L] 
RewriteRule ^forum/([a-zA-Z0-9_]+)_([0-9]+)/all/([0-9]+)$        index.php?controller=forum&action=showThread&urlTitle=$1&threadId=$2&page=$3 [L]
它目前的工作原理是,所有url都被定向到index.php,然后使用以下命令从url获取要使用的控制器和方法:

index.php

$actionName = $_GET['action'];
$controllerName = ucfirst(strtolower($_GET['type'])).'controller';

$controller = new $controllerName;
$controller->$actionName();
class forumcontroller{

    function showThread() {

        $thread = new Thread($_GET['threadId'], $_GET['uriTitle']); 
        require "templates/thread.php";
    }
controller/forumcontroller.php

$actionName = $_GET['action'];
$controllerName = ucfirst(strtolower($_GET['type'])).'controller';

$controller = new $controllerName;
$controller->$actionName();
class forumcontroller{

    function showThread() {

        $thread = new Thread($_GET['threadId'], $_GET['uriTitle']); 
        require "templates/thread.php";
    }
但这意味着用户可以访问我不希望他们也能访问的位置,例如:

/public_html/templates/index.php
我认为我需要什么?

我认为主.htaccess应该是这样的

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]
然后在index.php中,您将使用如下内容:

$url = explode("/", `$_SERVER['QUERY_STRING']);`

$controller = $url[0];   //Returns "forum"
$data = $url[1];         //Returns the forum title and id
 if(!$data)
     $controller->loadForum();
 elseif($data)
     $controller->loadForumThread($data);
但是使用这种方法,我不明白如何仅使用数据调用控制器内部的操作

难道你不需要做一些像:

$url = explode("/", `$_SERVER['QUERY_STRING']);`

$controller = $url[0];   //Returns "forum"
$data = $url[1];         //Returns the forum title and id
 if(!$data)
     $controller->loadForum();
 elseif($data)
     $controller->loadForumThread($data);
结论

我只是不知道如何最好地为一个有很多不同格式的seo友好URL的网站做路由,我知道mvc应该如何工作,但我正在努力掌握路由部分,我遇到的所有例子似乎都非常复杂

我真的很难理解如何编写
.htaccess
和控制器来处理不同格式的大量URL,如下所示:

domain.com
domain.com/uploads
domain.com/profiles/username
domain.com/messages/inbox
domain.com/messages/createnew/userId
domain.com/forum/all/2
domain.com/forum/title_1/
domain.com/forum/title_1/all/3

下面是一种类似于第二个.htaccess示例的方法

$request = explode('/', substr($_SERVER['REQUEST_URI'], 1));
// Clean request array of empty elements
foreach($request as $k => $v)
    // Clear any empty elements
    if(!$v) unset($request[$k]);
$request = array_values($request);  // Renumber array keys
这将提供一个数字索引数组,表示请求的URI。应用程序可以假定请求中的第一个值是控制器的名称:

if(count($this->request) == 0) 
    $request[] = 'DefaultController';  // Responsible for homepage
$this->controller = new $request[0]( $request );
我还将
$context
变量传递给控制器构造函数,但这超出了这个问题的范围(它负责数据库连接、当前用户数据和会话数据)

之后,它只发送请求:
$this->controller->dispatch()

在分派方法内部,控制器本身知道请求数组。例如,在URL列表中,让我们看第三个示例:
domain.com/profiles/username

控制器将命名为“Profiles”:

class Profiles {
    private $request, $context;
    public function __construct($request, $context) {
        $this->request = $request;
        $this->context = $context;
    }

    public function dispatch() {
        if(count($this->request) == 2 && $this->request[1] == 'username') {
            // Load data from model for the requested username ($this->request[1])

            // Show View
        }
    }
}

有更好的方法可以将请求向量映射到操作,但希望您得到jist。

什么是
$this->context=$context在您的示例中?出于我的目的,我使用上下文来存储请求的上下文。这不是100%适用于你的问题,所以我没有过多的细节。它基本上只是一个关联数组,包含对数据库、会话和用户对象的引用。@JeffLambert Howdy!我有一个关于PHP MVC路由的300点悬赏问题。如果您能提出任何意见,我们将不胜感激。祝你有美好的一天!我发现在我不想让用户访问的文件夹中使用.htaccess可能是一个更简单的解决方案,上面的路由方法有效,让我更容易控制url重写。有人不同意吗?