首先写一个例子,在siteController中覆盖behaviors函数

public function behaviors()
{
return [
'access' => [
'class'=>AuthFilter::className(),
'only'=>['index'],
],
'access11' => [
'class'=>AuthFilter::className(),
'only'=>['index'],
],
];
}


AuthFilter的定义

class AuthFilter extends ActionFilter
{
public function beforeAction($action)
{
echo 'this is echo when before Action';
return parent::beforeAction($action); // TODO: Change the autogenerated stub
}

public function afterAction($action, $result)
{
echo 'this is echo when after action';
return parent::afterAction($action, $result); // TODO: Change the autogenerated stub
}
}




我们知道controller的拦截器是在behavior中进行定义的,而controller的拦截器的函数必须定义beforeAction  和afterAction,这是为什么呢,因为这是当前Controller的祖父类定义的!!!

我的SiteController的父类是web的Controller,该类的父类是yii\base\controller,每次 一个请求的到来,都会执行祖父类Controller的runAction

public function runAction($id, $params = [])
{
$action = $this->createAction($id);
if ($action === null) {
throw new InvalidRouteException('Unable to resolve the request: ' . $this->getUniqueId() . '/' . $id);
}

Yii::trace('Route to run: ' . $action->getUniqueId(), __METHOD__);

if (Yii::$app->requestedAction === null) {
Yii::$app->requestedAction = $action;
}

$oldAction = $this->action;
$this->action = $action;

$modules = [];
$runAction = true;

// call beforeAction on modules
foreach ($this->getModules() as $module) {
if ($module->beforeAction($action)) { //这里执行了一次,调用点是yii\web\application
array_unshift($modules, $module);
} else {
$runAction = false;
break;
}
}

$result = null;

if ($runAction && $this->beforeAction($action)) { //可以看到,执行beforeAction之后,并且返回true,之后参会进行下一步操作
// run the action
$result = $action->runWithParams($params);

$result = $this->afterAction($action, $result);

// call afterAction on modules
foreach ($modules as $module) {
/* @var $module Module */
$result = $module->afterAction($action, $result);
}
}

$this->action = $oldAction;

return $result;
}


祖父类执行了beforeAction,但是大家需要注意的是beforeAction执行了两次,一次是web\application执行beforeAction,这样是不会执行我们controller中的behavior中的beforeAction函数的,而当执行$this->beforeAction的时候其定义如下:

public function beforeAction($action)
{
$event = new ActionEvent($action);
$this->trigger(self::EVENT_BEFORE_ACTION, $event);
return $event->isValid;
}

这样就触发了trigger函数,其函数定义如下:

public function trigger($name, Event $event = null)
{
$this->ensureBehaviors();
if (!empty($this->_events[$name])) {
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);//此处进行beforeAction的调用
// stop further handling if the event is handled
if ($event->handled) {
return;
}
}
}
// invoke class-level attached handlers
Event::trigger($this, $name, $event);
}

因为我们在$this 也就是siteController中定义了behaviors函数,在ensureBahaviors中就将behavior放在了component中的_behaviors数组当中,同时将对应的数据写在了_events当中,其$name 也是beforeAction,这样就会执行call_user_func函数,调用我们的接口

只是此时$name 是beforeAction,而 $handler是一个数组,第一个元素是定义类的对象,第二个是要执行的函数名称"beforeFilter",该函数的定义是在ActionFilter类中定义的

/**
* @param ActionEvent $event
*/
public function beforeFilter($event)
{
if (!$this->isActive($event->action)) {
return;
}

$event->isValid = $this->beforeAction($event->action);
if ($event->isValid) {
// call afterFilter only if beforeFilter succeeds
// beforeFilter and afterFilter should be properly nested
$this->owner->on(Controller::EVENT_AFTER_ACTION, [$this, 'afterFilter'], null, false);
} else {
$event->handled = true;
}
}


由该函数转调子类的beforeAction,这样就完成了我们的整个操作,需要注意的是如果有多个behavior的时候,则会根据behaviors数组的顺序,依次进行调用!!!