Yii中Action详解

在此篇中,主要介绍Yii是如何看待Action的。那么在Controller中又是如何如何处理Action的,Action又有哪些需要注意的特性呢?

带着这些问题,我们来看看下面的代码,里面会涉及到Yii Framework的process flow分析文中提到的一些基础,如果没有看过,建议先阅读之。

首先先看段代码,此段代码位于CController中

 1     public function createAction($actionID)
 2     {
 3         if($actionID==='')
 4             $actionID=$this->defaultAction;
 5         if(method_exists($this,'action'.$actionID) && strcasecmp($actionID,'s')) // we have actions method
 6             return new CInlineAction($this,$actionID);
 7         else
 8         {
 9             $action=$this->createActionFromMap($this->actions(),$actionID,$actionID);
10             if($action!==null && !method_exists($action,'run'))
11                 throw new CException(Yii::t('yii', 'Action class {class} must implement the "run" method.', array('{class}'=>get_class($action))));
12             return $action;
13         }
14     }

这段代码像我们展示了Yii是如何看待Action的,本质上来说Yii把所有action都看成一个独立的类,这个时候,你可能会奇怪,我们明明可以在Controller中使用以action开头的方法定义Action的方法的,没有见到有类的感觉。那么,请注意此段代码的第6行,这个表示如果在controller中存在对应的以action打头的Action(针对actionID),那么就会使用这个action方法,构造出一个CInlineAction类。这里先说下,9-11行,这里是利用actions这个方法返回的array,生成指定的Action类的实例,同时从第10行可以看出,构造一个Action一定要重写其run方法,尽管有时候用不到,否则会出错。我们这里主要以CInlineAction为例进行说明。

为了更好的解释CInlineAction,我们来看看其和CAtion的代码。

 1 class CInlineAction extends CAction
 2 {
 3     public function run()
 4     {
 5         $method='action'.$this->getId();
 6         $this->getController()->$method();
 7     }
 8
 9     public function runWithParams($params)
10     {
11         $methodName='action'.$this->getId();
12         $controller=$this->getController();
13         $method=new ReflectionMethod($controller, $methodName);
14         if($method->getNumberOfParameters()>0)
15             return $this->runWithParamsInternal($controller, $method, $params);
16         else
17             return $controller->$methodName();
18     }
19
20 }

先看看CInlineAction的代码,这里先重写了下run方法,正如我们说的是为了通过检查,主要是runWithParams。那么你一定奇怪,我们都了后面一个函数,为什么还要前者?这个是yii的历史遗留问题了。此处很简单就是写该如何执行action。接下来,是CAtion的代码

 1 abstract class CAction extends CComponent implements IAction
 2 {
 3     private $_id;
 4     private $_controller;
 5
 6     public function __construct($controller,$id)
 7     {
 8         $this->_controller=$controller;
 9         $this->_id=$id;
10     }
11
12     public function getController()
13     {
14         return $this->_controller;
15     }
16
17     public function getId()
18     {
19         return $this->_id;
20     }
21
22     public function runWithParams($params)
23     {
24         $method=new ReflectionMethod($this, 'run');
25         if($method->getNumberOfParameters()>0)
26             return $this->runWithParamsInternal($this, $method, $params);
27         else
28             return $this->run();
29     }
30
31     protected function runWithParamsInternal($object, $method, $params)
32     {
33         $ps=array();
34         foreach($method->getParameters() as $i=>$param)
35         {
36             $name=$param->getName();
37             if(isset($params[$name]))
38             {
39                 if($param->isArray())
40                     $ps[]=is_array($params[$name]) ? $params[$name] : array($params[$name]);
41                 else if(!is_array($params[$name]))
42                     $ps[]=$params[$name];
43                 else
44                     return false;
45             }
46             else if($param->isDefaultValueAvailable())
47                 $ps[]=$param->getDefaultValue();
48             else
49                 return false;
50         }
51         $method->invokeArgs($object,$ps);
52         return true;
53     }
54 }

这段代码也没有什么可以多说的。主要是__construct方法和runWithParamsInternal。

首先看看__construct,要注意这里传入了controller的实例和actionID,这两点一定要清楚。前者说明了此action的所在的controller,后者用于拼贴成method,供调用。接下来看看runWithParamsInternal,该方法是$_GET转换为参数,传入带参数的Action中。具体执行部分为第51行。
然后再来看看CAction继承了哪些,分别是CComponent和IAction,IAction没有什么可以多说的。一看代码变知了。

interface IAction
{
    /**
     * @return string id of the action
     */
    public function getId();
    /**
     * @return CController the controller instance
     */
    public function getController();
}

关键是CAction还继承自CComponent,所以CAction会拥有CComponent的所有特性,比较典型的就是behavior了。对于CComponent届时会有专门的一章着重介绍。毕竟他可是很多的基础。

 

实际上Yii中的action看似神秘,其实原理还是很简单的。





 » 转载请注明来源:AnyKoro Blog » 《Yii中Action详解》
 » 订阅本站:RSS订阅

发表评论

您也可以使用微博账号登陆

无觅相关文章插件,快速提升流量