在MVC架构中切换控制器

3

我正在尝试理解并找出在自己的框架中切换控制器的好方法。下面的示例是我目前在思考的,为了演示而简化了代码,但如果有更好的方法,我真的很希望能得到专家的建议?

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;
}

1
你是否计划允许框架用户实现自定义控制器和自定义操作? - bob-the-destroyer
@bob-the-destroyer 如果这样可以使代码更加通用,我认为是可以的。 - mister martin
2个回答

3

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

  1. Your BaseController in your example is probably misnamed. What you have in it makes it look more like a controller factory than a base controller all other controller classes might derive from. It looks like this is more of a "routing" class, so you should consider giving it a more appropriate name for its job.

  2. If you want your framework users to create custom controllers with custom actions:

    a) You'll definitely want to create at least an interface for all controller classes to implement. Call it IController or something like that. This is used in the next step.

    b) You'll have to settle for creating objects using strings as classnames. IE $controllerObject = new $controller(); within your "Route" handler class. The reason being is that controller and action names to run come straight from the request URL. There's ways of aliasing this part, but that's another question entirely. Do not forget to validate and/or whitelist these "controller" class names passed in from the client. To validate: use the PHP functions class_exists($controller) and then if true, check to make sure the controller class implements IController using PHP's built-in class_implements($controller). Only then should you do $controllerObject = new $controller(); to actually create the controller object.

    Your "Route" process method then becomes something more like (and keep in mind this is a very simplified example):

    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) Do not have your controller declare any method (ie named with the value of whatever $action may be) you do not want the client to execute directly using this above design pattern. Hopefully your framework users understand this as well. Just be sure to properly document how this works internally to make your framework users aware.

当然,除此之外还有更多内容需要考虑,但这就取决于你-框架设计者。此外,动作应该对使用哪个“视图”拥有最终决定权。如果操作未明确指定要使用的视图,则可以设置默认值。但这需要另一个问题来解决。


+1 重命名类。假设控制器有一个父基类,那么使用它的名称会是更好的选择。 - Peter

0

你真的应该先了解一下MVC是什么。我建议从Fowler的GUI Architectures开始阅读。因为有一件事是非常确定的 - 你所拥有的不是MVC。

看起来,你所命名的BaseController实际上处理的是路由。它获取用户请求的URL,并根据从该URL检索到的内容包含一个文件。这既不是面向对象编程,也不是过程式编程。你所拥有的被称为非结构化编程

与其这样做,你应该创建一个单独的类(或多个类),为你的应用程序实现路由机制。并且基于你使用这些结构提取的数据,你应该初始化特定的控制器实例,并调用其方法。

像这样:

$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. 您可能会发现以下链接对您的学习有用:this, this, thisthis


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