🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 说在前面 MVC模式下我们通常第一时间就在控制器的方法里写代码,在Yii里将这个写代码的地方定义了一个叫`Action`的概念,比如下面就有2个Action: ~~~php class UserController extends \yii\web\Controller{ public function actionRegister(){ //注册处理 } public function actionLogin(){ //登录处理 } } ~~~ 我们日常交流中就说“这个控制器里有2个方法分别处理注册和登录业务”,在Yii里应该说“这个控制器里有2个Action……” 方法就方法,干嘛要套个别的名头上去?且看下面 * * * ## Action映射 先定义一个类继承[yii\\base\\Action](http://www.yiichina.com/doc/api/2.0/yii-base-action): ~~~php namespace app\actions; class Login extends \yii\base\Action{ public function run(){ echo '登录处理'; } } ~~~ 然后控制器可以这样: ~~~php class UserController extends \yii\web\Controller{ //这个方法是重点!!!! public function actions(){ return [ //将login映射到指定的类 'login' => 'app\actions\Login' ]; } public function actionRegister(){ //注册处理 } } ~~~ 此时看上去只有`?r=user/register`能访问到actionRegister方法 但实际上`?r=user/login`也能访问,它会执行**app\\actions\\Login::run**,因为控制器的`actions`方法进行了actionID映射,它里面的意思是说:如果收到请求的actionID是`login`的话,那就大概这样: ~~~php $action = new \app\actions\Login(); $action->run(); ~~~ 这样就实现了将login逻辑剥离到一个独立的类里处理了,而且这个类还能被别的地方重用 假如登录逻辑的代码很长很复杂,写在这个Controller那加上别的业务代码量就会变得很大,我们可以尝试这样封装一下,我个人曾经也遇到过这样的项目,登录逻辑很复杂很长,而且登录后又要做一些事情 * * * ## 访问控制器 如果有多个控制器都定义了`actions`方法来映射到同一个Action类,那这个Action怎么知道是哪个控制器调用了自己呢?那就是`$this->controller`属性: ~~~php echo $this->controller->id; var_dump($this->controller); ~~~ * * * ## 访问actionId `$this->id` * * * ## 返回值 将业务逻辑封装到独立的Action中后,这个Action处理完业务要返回数据给前端时,做法跟平时控制器的方法是一模一样的,比如`return 123`或`return $this->controller->render('login')`或renderPartial等都行 * * * ## 属性注入 其实actions方法进行映射时也能进行属性注入,比如一个Action定义了$a、$b属性,那映射时可以这么来: ~~~php public function actions(){ return [ 'login' => [ //变成了数组 'class' => 'app\actions\Login', 'a' => 'value a', 'b' => 'value b', ] ]; } ~~~ 这样如果有多个控制器都将各自的请求映射给同一个Action时,但各个控制器的actions方法可以注入不同的属性值,以此来让这个Action能依据不同的属性值来进行不同的工作逻辑控制 **实际上这种需求很少,首先定义成独立Action的需求就很更少**,所以这个只要知道一下就好 * * * ## 好了,那为何叫Action 简单地说,如果将login方法定义成了一个独立的类(如上面的app\\actions\\Login),那这个类已经不能说它是控制器的login方法了 而是login业务通过一个类的逻辑来实现了而已,这个逻辑体叫什么呢,于是官方就起名为Action(行动)