Yii2.0的ActionFilter类详细解读

来源:互联网 发布:风暴英雄数据查询 编辑:程序博客网 时间:2024/06/03 17:29

1.涉及的属性和方法:

yii\base\ActionFilter中public function attach(){    把beforeFileter绑定到Controller的EVENT_BEFORE_ACTION事件上}public function detach(){    1.将beforeFileter从Controller的EVENT_BEFORE_ACTION事件上解绑    2.将afterFilter从Controller的EVENT_AFTER_ACTION事件上解绑}public function beforeFilter(){    调用self的beforeAction方法,    返回真则把afterFilter绑定到Controller的EVENT_AFTER_ACTION事件上    返回假。。。。?}public function afterFilter(){    调用self的afterAction方法    将afterFilter从Controller的EVENT_AFTER_ACTION事件上解绑}public function beforeAction(){    在子类中可以重写并自定义处理,默认返回true}public function afterAction(){    在子类中可以重写并自定义处理,默认返回true}

2.使用方式

我们的研究对象是ActionFilter和Controller,这一点要特别注意ActionFilter在controller的behaviors()方法中添加
例如:

public function behaviors(){    $behaviors = parent::behaviors();    $behaviors[        'access' => [            'class' => AccessComponent::className()//没有use的话需要写类的全名,即包括命名空间的类名,AccessComponent是ActionFilter的子类         ]    ];    return $behaviors;}

3.运行机制解析

A.首先我们需要了解一些yii2.0中关于行为的知识,需要深入了解的请移步:http://www.digpage.com/behavior.html

1).yii/base/Component中加入了对行为(behaviors)的支持

Component的ensureBehaviors()方法会获取behaviors()方法返回的数组【注1】,
将数组中配置的行为类通过Yii::createObject创建出对象【注2】,
并调用行为的attach方法(一般是注册一个事件)【注3】,
然后将行为对象放到_behaviors数组中【注4】

下面两段代码是yii/base/Component的源码public function ensureBehaviors(){    if ($this->_behaviors === null) {        $this->_behaviors = [];        foreach ($this->behaviors() as $name =>$behavior) { //【注1】            $this->attachBehaviorInternal($name, $behavior);         }    }}private function attachBehaviorInternal($name, $behavior){    if (!($behavior instanceof Behavior)) {        $behavior = Yii::createObject($behavior);//创建行为对象【注2】    }    if (is_int($name)) {//通过判断是否是索引来判断是否是匿名行为        $behavior->attach($this);//绑定事件【注3】        $this->_behaviors[] = $behavior;【注4】    } else {        if (isset($this->_behaviors[$name])) {//如果该行为已存在,则注销此行为            $this->_behaviors[$name]->detach();        }        $behavior->attach($this);【注3$this->_behaviors[$name] = $behavior;【注4】    }    return $behavior;}
2).

在component的__set,__get,__isset,__unset,__call,on,off,trigger,attachBehavior等方法中,都在调用了ensureBehaviors()方法。也就是说在你调用component对象中不存在的属性和方法,设置不存在的属性和方法,绑定事件,解绑事件,触发事件,绑定行为时,都会首先把behaviors()方法中声明的行为注册(即new 出对象,调用attach方法绑定事件,将行为对象储存到_behaviors属性中)。这么处理是Yii2.0懒加载,即需要用到的时候才会new

3).

还有一个事实是,yii2.0中的组件基本都继承自Component类,其中我们用到的Controller正是继承自Component

B.关于事件的知识

对于Yii2.0的事件,同一个事件可以绑定多个handler(即处理方法),当trigger这个事件的时候,handler会按绑定顺序执行。想要了解更多关于事件的知识,请移步:http://www.digpage.com/event.html

C.关于请求进入Yii2.0的生命周期(重点看如何进入特定Controller的Action)

1).入口脚本index.php
new yii\web\Application($config))->run();
2).run()方法,继承自yii\base\Application

其中有这么一段代码

$response = $this->handleRequest($this->getRequest());
3).handleRequest()方法,在子类yii\web\Application中重写

看这段代码

$result = $this->runAction($route, $params);
4).runAction方法,在yii\base\Module中

这里我们看到,它先new了Controller对象,然后调用controller的runAction方法来执行相应的Action

result = $controller->runAction($actionID, $params);
5).controller的runAction()方法,在yii\base\Controller中
$this->beforeAction($action)
6).beforeAction
$this->trigger(self::EVENT_BEFORE_ACTION, $event);yii\base\Component中public function trigger($name, Event $event = null){    $this->ensureBehaviors();//注册行为    if (!empty($this->_events[$name])) {//调用事件handler        if ($event === null) {            $event = new Event;        }        if ($event->sender === null) {            $event->sender = $this;        }        $event->handled = false;        $event->name = $name;        foreach ($this->_events[$name] as $handler) {            $event->data = $handler[1];            call_user_func($handler[0], $event);            // stop further handling if the event is handled            if ($event->handled) {                return;            }        }    }    // invoke class-level attached handlers    Event::trigger($this, $name, $event);}

D.有了以上知识,我们大体可以梳理下ActionFilter的实现机制了

在C的6)之后,$this->trigger会先调用我们在A中提到ensureBehaviors()方法:
1)注册行为(并调用attach()方法,ActionFilter的attach方法是给Controller的before action事件绑定这个类的beforeFilter方法),
2)然后顺序调用对应事件_events数组中的handler(根据A的分析,我们可以判断出:多个ActionFilter的beforeFilter方法是顺序绑定到controller的before action事件中的)

4.总结

一个大体的思路就是

1)request进入index.php
2)new application并执行run
3)new Controller并执行runAction
4)runAction先执行beforeAction
5)beforeAction调用trigger方法,触发before action
6)trigger方法先注册行为,

对于ActionFilter行为来说,在注册过程中会按行为定义的顺序给controller的before action事件添加handler,其中每个handler就是对应的ActionFilter的beforeFilter方法,因为beforeFilter方法会调用它自己的beforeAction方法,可以认为handler就是每一个ActionFilter的beforeAction方法。

7)注册完后,顺序执行before action的handler

自此ActionFilter的功能告一段落,至于afterFilter,读者可以自行梳理,原理差不多是一致的
个人博客链接http://www.tanklh.cc/typecho/index.php/archives/4/

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 学生考试粗心该怎么办 高三学生失眠怎么办 期末考试考差了怎么办 小孩考试太粗心怎么办 带孩子太粗心怎么办 小孩做数学粗心怎么办 小学一年级学生厌学怎么办 小学二年级厌学怎么办 做题做的烦躁了怎么办 英语不会做题怎么办 孩子审题不细心怎么办 生孩子有恐惧症怎么办 小孩不喜欢上幼儿园怎么办 小孩不喜欢去幼儿园怎么办 小孩不喜欢学生字怎么办 学生不喜欢补课老师怎么办 小孩不喜欢上学逃课怎么办 一年级小朋友不爱写字怎么办 幼儿园小朋友不爱写字怎么办 孩子懒散不积极怎么办 孩子不肯上幼儿园怎么办 孩子不肯去幼儿园怎么办 小孩记不住字怎么办 小孩不会写字要怎么办 一年级孩子不爱写字怎么办 一年级小孩不爱写字怎么办 孩子不爱写字怎么办呢 幼儿园孩子不爱写字怎么办 孩子上学没学籍怎么办 孩子上学务工证怎么办 孩子上学被欺负怎么办 孩子害怕上幼儿园怎么办 孩子写字肩膀疼怎么办 5岁不会写字怎么办 上中班不爱写字怎么办 孩子性子太慢怎么办 13小孩特别懒怎么办 小孩不肯上幼儿园怎么办 宝宝不肯上幼儿园怎么办 宝宝不肯去幼儿园怎么办 小孩子不肯去幼儿园怎么办