【问题标题】:Switching between controllers (MVC)在控制器之间切换 (MVC)
【发布时间】:2012-12-27 06:22:59
【问题描述】:

我正在尝试理解并找出一种在我的自定义框架中切换控制器的好方法。以下示例是我目前的想法,出于演示目的进行了简化,但如果有更好的方法,我真的很感谢专家的建议?

class BaseController() {
    function __construct() {
        $this->model = new ModelFactory();
        $this->view = new View();

        if(isset($_SERVER['QUERY_STRING'])) {
            list($controller, $action) = explode('=', $_SERVER['QUERY_STRING']);
            self::process($controller);
        }
    }

    public function process($controller) {
        switch($controller) {
            case 'user':
                $user = new UserController($action);
            break;

            case 'forum':
                $forum = new ForumController($action);
            break;

            default:
                // use base controller
                switch($action) {
                    case 'contact':
                        $this->view->load($action);
                    break;
                }
        }
    }
}

// inside UserController.php
switch($action) {
    case 'register':
    break;

    case 'login':
    break;
}

// inside ForumController.php
switch($action) {
    case 'new_thread':
    break;

    case 'edit_post':
    break;
}

【问题讨论】:

  • 您是否计划允许您的框架用户使用自定义操作来实现自定义控制器?
  • @bob-the-destroyer 如果这会使代码更加通用,我假设它会,那么是的。

标签: php oop model-view-controller


【解决方案1】:

这确实是一个部分答案,希望能给你一些好的指导。我相信会有更好的答案的人出现。

  1. 您的示例中的BaseController 可能命名错误。你所拥有的使它看起来更像一个控制器工厂,而不是所有其他控制器类可能派生的基本控制器。看起来这更像是一个“路由”类,所以你应该考虑给它一个更适合它的工作的名字。

  2. 如果您希望您的框架用户使用自定义操作创建自定义控制器:

    a) 您肯定希望至少为所有控制器类创建一个接口来实现。称它为IController 或类似名称。这将在下一步中使用。

    b) 您必须适应使用字符串作为类名来创建对象。 IE $controllerObject = new $controller(); 在您的“Route”处理程序类中。原因是要运行的控制器和操作名称直接来自请求 URL。这部分有别名的方法,但这完全是另一个问题。 不要忘记验证和/或将这些从客户端传入的“控制器”类名列入白名单。验证:使用 PHP 函数 class_exists($controller),如果是 true,检查以确保控制器类使用 PHP 的内置 class_implements($controller) 实现 IController。只有那么您应该使用$controllerObject = new $controller(); 来实际创建控制器对象。

    您的“路线”process 方法会变得更像(请记住,这是一个非常简化的示例):

    public function process($controller, $action) {
        if (!class_exists($controller)) {
            throw new Exception('Controller class does not exist.');
        }
        if (!in_array("IController", class_implements($controller))) {
            throw new Exception('Route is not a valid controller.');
        }
        if (!method_exists($controller, $action)) {
            throw new Exception('No such action for requested controller.');
        }
        $ctrl = new $controller();
        return $ctrl->$action();
    }
    

    c) 不要让您的控制器声明任何您不希望客户端使用上述设计模式直接执行的方法(即使用任何$action 的值命名)。希望您的框架用户也能理解这一点。请务必正确记录其内部工作原理,以使您的框架用户了解。

当然还有比这更多的方法,但这取决于你 - 框架设计者。此外,操作应该对使用什么“视图”拥有最终决定权。如果操作没有明确说明要使用的视图,则可以设置默认值。但同样,那将是另一个问题。

【讨论】:

  • +1 用于重命名课程。假设控制器有一个父基类,它是一个更好的名称选择。
【解决方案2】:

您真的应该从阅读 MVC 的真正含义开始。我建议从 Fowler 的 GUI Architectures 开始。因为有一件事是非常确定的——你所拥有的不是它。

看起来,你所命名的BaseController,实际上是在处理路由。这就是用户的请求 URL,并包含基于您从所述 URL 检索到的文件的文件。这既不是面向对象编程,也不是过程编程。你在那里的东西被称为non-structured programming

您应该创建一个单独的类,而不是这种疯狂,为您的应用程序实现路由机制。并且根据您使用所述结构提取的数据,您应该启动特定的控制器实例,并在其上调用方法。

类似:

$request = new Request('QUERY_STRING');

$router = new Router;
$router->import('/path/to/routing/config.file');
$router->route( $request );

$klass = $request->getParameter('controller');

if (class_exists( $controller ))
{
    $command = $request->getMethod() . $request->getParameter('action');
} 
else 
{
    $klass = 'Error';
    $command = 'getMessage';
}

$controller = new $klass;
$controller->{$command}( $request );

这当然是一个极其简化的版本。 MVC 模式旨在为大型项目带来一些秩序。如果你用它来创建一个简单的博客/名片网站,这似乎有点过头了(假设页面没有增长)。

P.S.您可能会发现以下链接对您的学习有用:thisthisthisthis

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-09
    • 2019-04-10
    • 1970-01-01
    • 2011-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多