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
}
我们的研究对象是ActionFilter和Controller,这一点要特别注意ActionFilter在controller的behaviors()方法中添加
例如:
public function behaviors() {
$behaviors = parent::behaviors();
$behaviors[
'access' => [
'class' => AccessComponent::className()//没有use的话需要写类的全名,即包括命名空间的类名,AccessComponent是ActionFilter的子类
]
];
return $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;
}
在component的__set,__get,__isset,__unset,__call,on,off,trigger,attachBehavior等方法中,都在调用了ensureBehaviors()方法。也就是说在你调用component对象中不存在的属性和方法,设置不存在的属性和方法,绑定事件,解绑事件,触发事件,绑定行为时,都会首先把behaviors()方法中声明的行为注册(即new 出对象,调用attach方法绑定事件,将行为对象储存到_behaviors属性中)。这么处理是Yii2.0懒加载,即需要用到的时候才会new
还有一个事实是,yii2.0中的组件基本都继承自Component类,其中我们用到的Controller正是继承自Component
对于Yii2.0的事件,同一个事件可以绑定多个handler(即处理方法),当trigger这个事件的时候,handler会按绑定顺序执行。想要了解更多关于事件的知识,请移步:http://www.digpage.com/event.html
new yii\web\Application($config))->run();
其中有这么一段代码
$response = $this->handleRequest($this->getRequest());
看这段代码
$result = $this->runAction($route, $params);
这里我们看到,它先new了Controller对象,然后调用controller的runAction方法来执行相应的Action
result = $controller->runAction($actionID, $params);
$this->beforeAction($action)
$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);
}
在C的6)之后,$this->trigger会先调用我们在A中提到ensureBehaviors()方法:
1)注册行为(并调用attach()方法,ActionFilter的attach方法是给Controller的before action事件绑定这个类的beforeFilter方法),
2)然后顺序调用对应事件_events数组中的handler(根据A的分析,我们可以判断出:多个ActionFilter的beforeFilter方法是顺序绑定到controller的before action事件中的)
对于ActionFilter行为来说,在注册过程中会按行为定义的顺序给controller的before action事件添加handler,其中每个handler就是对应的ActionFilter的beforeFilter方法,因为beforeFilter方法会调用它自己的beforeAction方法,可以认为handler就是每一个ActionFilter的beforeAction方法。
自此ActionFilter的功能告一段落,至于afterFilter,读者可以自行梳理,原理差不多是一致的
个人博客链接http://www.tanklh.cc/typecho/index.php/archives/4/