2

我正在尝试使用前端控制器设计深入研究 MVC。

我想通过使用一行来调用我的整个应用程序,例如在 index.php 中:

require_once(myclass.php);
$output = new myClass();

我很想摆脱 require_once 行,但我不明白如何在不包含它的情况下加载我的课程?

无论如何,我的主要问题是如何使用一个前端类加载我的各种控制器、模型和视图等。到目前为止,我想出了:

class myClass
{
    private $name;
    public $root = $_SERVER['DOCUMENT_ROOT'];
    private $route = array("Controller" => "", "Model" => "", "View" => "", "Paremeters" => "");
    function __construct() 
    {   $uri = explode("/",$_SERVER['REQUEST_URI']);
        if(isset($uri[2])) {$this->route['Controller'] = $uri[2];}
        if(isset($uri[3])) {$this->route['Model'] = $uri[3];}
        if(isset($uri[4])) {$this->route['View'] = $uri[4];}
        if(isset($this->route['Controller'])) 
        {
            include($this->root."/".$this->route['Controller'].".php");
        }
    }

}

但这似乎有点令人费解并且过于夸张。另外,一旦我在 __construct 中包含了新类,我应该如何加载它?

我很抱歉缺乏知识,我已经用谷歌搜索了很多次,并且我不断提出相同的页面,这些页面似乎并没有扩展我对此事的了解。

4

3 回答 3

5

如果您的 URL 肯定是http://domain.com/[controller]/[action]/ parameters,那么您的前端控制器可能如下所示:

<?php
class Application
{
    public function __construct()
    {
        $this->setupAutoloader();
        $this->route();
    }

    private function setupAutoloader()
    {
        // do your autoloading here
    }

    private function route()
    {
        $request = explode('/', trim($_SERVER['REQUEST_URI'], '/'));

        $controller = isset($request[0]) ? ucwords(array_shift($request)) . 'Controller' : 'HomeController';
        $action = isset($request[0]) ? array_shift($request) : 'index';
        $parameters = $request;

        $response = call_user_func_array(array($controller, $action), $parameters);
    }
}

从这里,你可以添加你的自动加载器实现,对你的响应做任何你想做的事情,并从你的index.php调用它,如下所示:

<?php
require 'path/to/Application.php';

$application = new Application();

不幸的是,如果第一个文件存储在文件系统的其他位置,您总是必须包含第一个文件,但如上所述,您可以从这里自动加载其他类,例如库、控制器、模型等。

于 2012-11-19T14:30:54.463 回答
3

令我惊讶的是,在这两个冗长且内容丰富的先前答案中,没有人费心以最简单的方式实际回答您的问题。

你想要这个__autoload()功能。您仍然必须在代码中的某处定义它,但可以简单地将其添加到全局头文件中,然后您不必为每个类定义显式编写包含。

/* auto load model classes */
function __autoload($class_name) {
        $filename = 'class.' . strtolower($class_name) . '.php';
        $file = __SITE_PATH . '/_model/' . $filename;
        if( file_exists($file) == false ) {
                return false;
        }
        require($file);
}
于 2012-11-19T16:07:05.983 回答
1

为了在不手动包含的情况下加载类,您应该查看spl_autoload_register,它使您能够在应用程序需要时自动加载类。

至于另一个问题,这完全取决于您的设计。如果要加载通用的“控制器”和“动作”,则应创建一个可路由文件夹(即只有控制器可以停留的文件夹)并放置所有控制器类,然后创建一个可路由动作空间(可路由组控制器类中的方法,通常是通过定义动作方法以action_) 为前缀的约定。完成后,只需像这样创建控制器:

class Blog {
    public function action_posts() { ... };
}

并管理它,以便 URL/blog/posts/调用它。(它只需要你已经证明擅长的相同的 URI 操作)。(请注意,自动加载器应该自己处理实际类文件的包含,而不需要您加载所有控制器类)。获得控制器名称和操作后,您只需要以下内容:

if (class_exists($controller)) {
    $app = new $controller;
    if (method_exists($app, $action)) {
        $app->$action(); // also take a look at call_user_func and call_user_func_array
    }
}

您也可以允许参数,但这将非常困难,以允许这种结果:

class Blog {
    public function action_post($id) { ... };
}

并被/blog/post/14/例如调用。

在处理 URI 时,请记住您可能有错误的输入并且您应该处理它们,但是如果您创建了正确的路由空间,那么您已经完成了一半。

最后,如果您想获得灵感或其他任何东西,只需看看 CodeIgniter(这是最容易学习的框架之一)或任何其他框架。

希望它有所帮助。

于 2012-11-19T14:22:00.750 回答