7.3. 子类化（继承）
上一页 | 第 7 章 Zend_Controller | 下一页

## 7.3. 子类化（继承）

### 7.3.1. 简介

Zend_Controller体系具有可扩展性，可以通过继承已有的类或者自己写个新的类来实现Zend_Controller_Router_Interface或Zend_Controller_Dispatcher_Interface接口。

打算实现一个新的router或dispatcher的原因可能是：

- 已有的URI routing系统不合适，如把用Zend Framework的站点集成到一个已经存在的有自己的定向规则的站点。

- 你想用MVC模式来开发其它形式的PHP程序，如命令行形式的。那么你就需要自己定制一个router来处理命令行的参数了。

- Zend_Controller_Dispatcher提供的机制不适用于你的程序。默认的情况是controller是类而action是类中的方法。但是也有其它情况如controller是一个目录，而action是其中的文件。这样你也要自己写。

- 你想为你的控制器提供更多功能。例如Zend_Controller_Action默认没有和Zend_View集成。当然你也可以通过继承来实现，这样可以不用改变Zend_Controller_Router或者Zend_Controller_Dispatcher。

P当你覆写系统的重要部分时要非常小心，特别是dispatcher。Zend_Controller的优点之一是它对于构建各种应用程序规定了一些固定的规则。如果你改写太多，有可能就失去这个优点。不过，现实当中有各种不同的需要，不可能只采用一种解决方案，所以在需要的时候可以考虑自己来改写。

### 7.3.2. 约定（规则）

当继承任何Zend_Controller的类时，你最好遵循以下命名和文件存储规则。这样做可以让另一个熟悉Zend Framework的程序员很容易地理解你的项目。

#### 7.3.2.1. 前缀

Zend Framework中的所有类的名称都有一个前缀“Zend_” ，我们建议你的类可以模仿这种方法，例如你的公司名称为Widget，则前缀可以是“Widget_” 。

#### 7.3.2.2. 目录分布

Zend_Controller的各个类在library目录下是这样分布的：

    /library
      /Zend
        /Controller
          Action.php
          Dispatcher.php
          Router.php

当继承Zend_Controller类时，建议新的类放在带有你的前缀的和以上结构完全相同的目录下。这样别人在查看你的代码时，可以很容易找到相应的代码。

例如，Widget公司的一个项目，只实现了一个自定义的router，看起来可能是这样的：

    /library
      /Zend
      /Widget
        /Controller
          Router.php
          README.txt

注意在这个例子中Widget/Controller/映射到Zend/Controller/。另外，这个例子提供了一个Widget_Controller_Router，这可能是Zend_Controller_Router的子类，也可以是替代（通过实现Zend_Controller_Router_Interface接口）。

同时，注意上例中在Widget/Controller/下有个README.txt文件。我们强烈建议你为客户提供各种测试和文档，同时也建议你放置一个简单的README.txt文件在适当的目录，用来简要说明代码的修正过程和它们是如何工作的。

### 7.3.3. Router 接口

Zend_Controller_Router_Interface接口只定义了一个方法：

    <?php

      /**
       * @param  Zend_Controller_Dispatcher_Interface
       * @throws Zend_Controller_Router_Exception
       * @return Zend_Controller_Dispatcher_Token|boolean
       */
      public function route(Zend_Controller_Dispatcher_Interface $dispatcher);

    ?>

Routing过程只发生一次：当请求被系统接收时。router的目的在于生成一个描述controller和action的Zend_Controller_Dispatch_Token。Token对象被传给dispatcher。如果无法将一个路径分配到一个dispatch token(无效的访问路径)，则会返回false。

一些router需要处理动态的元素，需要判断生成的dispatch token在return之前是否是可分配的。 出于这个原因，router把对象当成它的route()方法的唯一的参数 。 dispatcher则提供了一个 isDispatchable()方法来测试是否是可分配的。

### 7.3.4. Dispatcher 接口

Zend_Controller_Front会先调用router，接收第一个dispatch token，然后传递给dispatcher。dispatcher将分配action(实例化一个controller，调用它的action)并返回一个FALSE或者另一个 dispatch token。

Zend_Controller_Front重复调用dispatcher直到不返回dispatch token为止。这就是所谓的dispatch循环，它让所有的action依次处理，直到处理完毕。

Zend_Controller_Dispatcher_Interface接口定义了两个方法：

    <?php

    /**
     * @param  Zend_Controller_Dispatcher_Token $route
     * @return boolean
     */
    public function isDispatchable(Zend_Controller_Dispatcher_Token $route);

    ?>

isDispatchable()方法检查一个 dispatch token 是否是可分配的。如果可以，返回TRUE，否则返回FALSE。默认地对于Zend_Controller_Dispatcher，可分配的意思就是说controller文件存在，文件内也存在相应的类，并且类中存在相应的action方法，

    <?php

    /**
     * @param  Zend_Controller_Dispatcher_Token $route
     * @return Zend_Controller_Dispatcher_Token|boolean
     */
    public function dispatch(Zend_Controller_Dispatcher_Token $route);

    ?>

dispatch()方法就是action执行的地方，必须执行controller的action。它可以返回一个dispatch token或者返回一个FALSE，表示工作已经全部完成。

上一页 | 上一级 | 下一页
7.2. 入门 | 起始页 | 7.4. Provided Subclasses