前端控制器模式的介绍,第1部分

来源:互联网 发布:回声电影软件 编辑:程序博客网 时间:2024/06/14 22:23
有趣的是要看到人如何通过对几个软件编程的概念,在一个拟人化的方式判断。脂肪模型都是甜的和良好的,臃肿的控制器是邪恶的,单身充满untameable陷阱。但批评者不要停在那里,有的正在抱怨新概念最近在一天到一天的PHP开发进军,说前端控制器冗余“再造轮子”,这应该被丢弃事实上。时期。
投球不时对单身人士的指责,甚至有点胡思乱想关于脂肪控制器,在一定程度上,是相当可预见的和健康的反应。但是,什么是错的,有一个漂亮的前端控制器和运行?
对前端控制器有一个相当可观的论点。在基于网络的应用程序的前端控制器的主要作用是封装典型的请求/路由/调度/响应周期容易消耗的API,这是Web服务器没有什么界限内。事实上这个过程似乎是多余的,乍一看,但加上一个MVC实现时,我们实际上是在试图建立一个控制器,反过来控制其他控制器。
尽管明显重复的角色,出现一个前端控制器实现,以应对日益复杂的现代Web应用程序开发。隧道所有的请求通过一个单一的入口点,无疑是一个有效的方式来执行命令的机制,这不仅可以让你的路由和调度命令相应的处理程序,但也暴露了一个灵活的结构,没有太多的负担,可以按摩和缩放。
老实说,前端控制器是容易驯服的动物。在最简单的场景,一个天真的组合URL重写几个开关语句是我们所需要的路由和调度要求,但在生产,可能有必要呼吁更加复杂和精细的实现,特别是如果我们想提取路由通过细粒度的对象调度进程配备隔离的责任。
在这个由两部分组成的文章中,我将深入探讨了几个简单的方法,你会发现吸引力,特别是如果你想从头开始实施一个可扩展的前端控制器,没有过分出汗过程中,或有配合一个臃肿框架的负担。
 
一个简单的方法在路由和调度
 
在现实中,有这么多漂亮的选项,可用于建立一个功能的前端控制器使用,但我会开始让我的务实的一面展现(是的,我有一个)。将收取第一的前端控制器实现,我会去通过路由/调度的URI符合下列格式:

basepath/controllername/actionname/param1/param2/.../paramN

如果你曾经你的手放在了一个框架,使用参数化的动作控制器的概念,上面的URI应该熟悉。这是一个相当无处不在的模式。当然,这里最艰巨的任务是设计一个灵活的机制,能够解析URI的问题,没有什么大惊小怪的。这样就可以实现在所有创造性的方式排序,无论是普通的程序代码或呼吁面向对象的代码。我将封装/下一个单一的类壳路由调度逻辑的螺母和螺栓:

01<?php
02namespace Library\Controller;
03
04interface FrontControllerInterface
05{
06    public function setController($controller);
07    public function setAction($action);
08    public function setParams(array $params);
09    public function run();
10}
01<?php
02namespace Library\Controller;
03
04class FrontController implements FrontControllerInterface
05{
06    const DEFAULT_CONTROLLER = "IndexController";
07    const DEFAULT_ACTION     = "index";
08     
09    protected $controller    = self::DEFAULT_CONTROLLER;
10    protected $action        = self::DEFAULT_ACTION;
11    protected $params        = array();
12    protected $basePath      = "mybasepath/";
13     
14    public function __construct(array $options = array()) {
15        if (empty($options)) {
16           $this->parseUri();
17        }
18        else {
19            if (isset($options["controller"])) {
20                $this->setController($options["controller"]);
21            }
22            if (isset($options["action"])) {
23                $this->setAction($options["action"]);    
24            }
25            if (isset($options["params"])) {
26                $this->setParams($options["params"]);
27            }
28        }
29    }
30     
31    protected function parseUri() {
32        $path = trim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), "/");
33        $path = preg_replace('/[^a-zA-Z0-9]\//', "", $path);
34        if (strpos($path, $this->basePath) === 0) {
35            $path = substr($path, strlen($this->basePath));
36        }
37        @list($controller, $action, $params) = explode("/", $path, 3);
38        if (isset($controller)) {
39            $this->setController($controller);
40        }
41        if (isset($action)) {
42            $this->setAction($action);
43        }
44        if (isset($params)) {
45            $this->setParams(explode("/", $params));
46        }
47    }
48     
49    public function setController($controller) {
50        $controller = ucfirst(strtolower($controller)) . "Controller";
51        if (!class_exists($controller)) {
52            throw new \InvalidArgumentException(
53                "The action controller '$controller' has not been defined.");
54        }
55        $this->controller = $controller;
56        return $this;
57    }
58     
59    public function setAction($action) {
60        $reflector = new \ReflectionClass($this->controller);
61        if (!$reflector->hasMethod($action)) {
62            throw new \InvalidArgumentException(
63                "The controller action '$action' has been not defined.");
64        }
65        $this->action = $action;
66        return $this;
67    }
68     
69    public function setParams(array $params) {
70        $this->params = $params;
71        return $this;
72    }
73     
74    public function run() {
75        call_user_func_array(array(new $this->controller, $this->action), $this->params);
76    }
77}

FrontController类的职责归结为解析请求的URI,或者最终通过一些基本的存取器装配从头开始新的品牌。一旦这项任务已经开展,整齐的run()方法调度到适当的行动控制器的请求,提供的参数,如果有的话。
鉴于其最小的API,消费类是一个简单的过程分为两个步骤。首先,拖放到网站的根1典型的htaccess文件。文件,像这样的:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php

第二,建立下面的代码片断的index.php:

01<?php
02use Library\Loader\Autoloader,
03    Library\Controller\FrontController;
04     
05require_once __DIR__ . "/Library/Loader/Autoloader.php";
06$autoloader = new Autoloader;
07$autoloader->register();
08
09$frontController = new FrontController();
10$frontController->run();

在这种情况下,控制器简单解析请求的URI和饲料给定的动作控制器,这是它的默认行为的方式。虽然,这是可行的,明确规定由一个URI调用相应的setter方法​​,如下:

1 <?php
2 $frontController = new FrontController(array(
3     "controller" => "test",
4     "action"     => "show",
5     "params"     => array(1)
6 ));
7
8 $frontController->run();

 
这里的前端控制器是相当的可塑性,易于内部解析请求或直接从客户端代码提供自定义的路由/调度配置。此外,前面的例子显示了在简而言之如何调用的show()一个假设方法TestController类的,在一个单一的数字参数传递给它的。当然,它可以随意使用不同的URI和发挥控制器的能力。因此,如果你厌倦,并希望有一些免费的乐趣,只要继续这样做。
虽然我不得不承认,我精心制作的FrontController类已相当有限的功能,它使自身的声明。它表明,建立一个可定制的前端控制器实际上是一个简单的过程,可以成功地驯服,而不必使用晦涩和纠结的编程原则。
在另一方面,坏消息是,班上有很多责任的方式来观看了。如果你怀疑,只是检查出它的run()方法。当然,它的实施是干净的,紧凑,甚至可以容纳拦截前/后派遣挂钩。但它确实在同一时间多个事物和行为作为一个包罗万象的路线和调度点相当多。这是可取的,有一个前端控制器在更精细的类解剖,其收窄至离散任务的执行的责任。
不用说,让这样的蒸馏水的前端控制器和按预期运行,需要在道路上行驶的类和接口的数量相当多产。我不愿意让本批过于冗长,所以我将在下一篇文章中涉及的整个实施过程中的细节深入。这种方式可以有一些时间来扭转和弯曲我的样品前端控制器,使其适合您的微妙的口味的味道。
关闭的思考
前端控制器是可笑的简单实现从无到有,无论如果该方法的程序代码或使用面向对象的代码。并且由于其随和的天性,它很容易扩展了一个天真,原始的前端控制器和幕后处理RESTful资源所需的全部家当,在其肩上的音调。
很可能,写一个前端控制器最纠结的一个方面是解决隐含的困境时,它要决定,如果要求必须静态或动态路由,并派出相应的处理程序。有没有正式的原则,规定所有的路由/调度逻辑被封装在控制器的边界或分解成独立的模块,可以独立重用。
确切地说,后者是,我将讨论过,当然在下一篇文章中的实现形式。所以,敬请期待!

站长行业门户(www.software8.co)文章,希望大家可以留言建议