7.4. 请求对象

7.4.1. 介绍

请求对象是在前端控制器,路由器,分发器,以及控制类间传递的简单值对象。请求对象封装了请求的模块,控制器,动作以及可选的参数,还包括其他的请求环境,如HTTP,CLI,PHP-GTK。

  • 模块名可通过getModuleName()setModuleName()访问。

  • 控制器名可通过getControllerName()setControllerName()访问。

  • 控制器调用的动作名称可通过getActionName()setActionName()访问。

  • 可选参数是一个键值对的关联数组。数组可通过getParams()setParams()获取及设置,单个参数可以通过 getParam()setParam()获取及设置。

基于请求的类型存在更多的可用方法。默认的Zend_Controller_Request_Http请求对象,拥有访问请求url、路径信息、$_GET$_POST参数的方法等等。

请求对象先被传入到前端控制器。如果没有提供请求对象,它将在分发过程的开始、任何路由过程发生之前实例化。请求对象将被传递到分发链中的每个对象。

而且,请求对象在测试中是很有用的。开发人员可根据需要搭建请求环境,包括模块、控制器、动作、参数、URI等等,并且将其传入前端控制器来测试程序流向。如果与响应对象配合,可以对MVC程序进行精确巧妙的单元测试(unit testing)。

7.4.2. HTTP 请求

7.4.2.1. 访问请求数据

Zend_Controller_Request_Http封装了对相关值的访问,如控制器和动作路由器变量的键名和值,从URL解析的附加参数。它还允许访问作为公共成员的超全局变量,管理当前的基地址(Base URL)和请求URI。超全局变量不能在请求对象中赋值,但可以通过setParam/getParam方法设定/获取用户参数。

[注意] 超全局数据

通过Zend_Controller_Request_Http访问公共成员属性的超全局数据,有必要认识到一点,这些属性名(超全局数组的键)按照特定次序匹配超全局变量:1. GET,2.POST,3. COOKIE,4. SERVER,5. ENV。

特定的超全局变量也可以选择特定的方法来访问,如$_POST['user']可以调用请求对象的getPost('user')访问,getQuery()可以获取$_GET元素,getHeader()可以获取请求消息头。

[注意] GET和POST数据

需要注意:在请求对象中访问数据是没有经过任何过滤的,路由器和分发器根据任务来验证过滤数据,但在请求对象中没有任何处理。

可以在请求对象中使用setParam()getParam()来设置和获取用户参数。 路由器根据请求URI中的参数,利用这项功能请求对象设定参数。

[注意] getParam()不只可以获取用户参数

getParam()事实上从几个资源中获取参数。根据优先级排序:通过setParam()设置的用户参数,GET 参数, POST参数,最后是COOKIE参数。 通过该方法获取数据时需要注意这点。

[注意] Apache相关

如果使用apache的404处理器来传递请求到前端控制器,或者使用重写规则(rewrite rules)的PT标志,URI包含在$_SERVER['REDIRECT_URL'],而不是$_SERVER['REQUEST_URI']。如果使用这样的设定并获取无效的路由,应该使用Zend_Controller_Request_Apache404类代替默认的HTTP类:


<?php
require_once 'Zend/Controller/Request/Apache404.php';
$request = new Zend_Controller_Request_Apache404();
$front->setRequest($request);

这个类继承了Zend_Controller_Request_Http,并简单的修改了请求URI的自动发现(autodiscovery),它可以用来作为简易替换器件(drop-in replacement)。

7.4.2.2. 基地址和子目录

Zend_Controller_Request_Http允许在子目录中使用Zend_Controller_Router_RewriteZend_Controller_Request_Http试图自动的检测你的基地址,并进行相应的设置。

例如,如果将 index.php 放在web服务器的名为/projects/myapp/index.php子目录中,基地址应该被设置为/projects/myapp。计算任何路由匹配之前将先从路径中去除这个字符串。这个字串需要被加入到任何路由前面。路由 'user/:username'将匹配类似http://localhost/projects/myapp/user/martelhttp://example.com/user/martel的URL。

[注意] URL检测区分大小写

基地址的自动检测是区分大小写的,因此需要确保URL与文件系统中的子目录匹配。否则将会引发异常。

如果基地址经检测不正确,可以利用Zend_Controller_Request_Http或者Zend_Controller_Front类的setBaseUrl()方法设置自己的基路径。Zend_Controller_Front设置最容易,它将导入基地址到请求对象。定制基地址的用法举例:


<?php
/**
 * Dispatch Request with custom base URL with Zend_Controller_Front.
 */
$router     = new Zend_Controller_Router_Rewrite();
$controller Zend_Controller_Front::getInstance();
$controller->setControllerDirectory('./application/controllers')
           ->
setRouter($router)
           ->
setBaseUrl('/projects/myapp'); // set the base url!
$response   $controller->dispatch();

7.4.3. 子类化请求对象

所有请求对象的基请求类是抽象类Zend_Controller_Request_Abstract。定义了一些最基本的方法:


abstract class Zend_Controller_Request_Abstract
{
    /**
     * @return string
     */
    public function getControllerName();

    /**
     * @param string $value
     * @return self
     */
    public function setControllerName($value);

    /**
     * @return string
     */
    public function getActionName();

    /**
     * @param string $value
     * @return self
     */
    public function setActionName($value);

    /**
     * @return string
     */
    public function getControllerKey();

    /**
     * @param string $key
     * @return self
     */
    public function setControllerKey($key);

    /**
     * @return string
     */
    public function getActionKey();

    /**
     * @param string $key
     * @return self
     */
    public function setActionKey($key);

    /**
     * @param string $key
     * @return mixed
     */
    public function getParam($key);

    /**
     * @param string $key
     * @param mixed $value
     * @return self
     */
    public function setParam($key, $value);

    /**
     * @return array
     */
     public function getParams();

    /**
     * @param array $array
     * @return self
     */
    public function setParams(array $array);

    /**
     * @param boolean $flag
     * @return self
     */
    public function setDispatched($flag = true);

    /**
     * @return boolean
     */
    public function isDispatched();
}

请求对象是请求环境的容器。控制器链实际上只需要知道如何设置和获取控制器、动作,可选的参数以及分发的状态。默认的,请求将使用controller和action键查询自己的参数来确定控制器和动作。

需要一个请求类来与特定的环境交互以获得需要的数据时,可以扩展该基类或它的衍生类。例如HTTP环境,CLI环境,或者PHP-GTK环境。