首先寫一個例子,在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數組的順序,依次進行調用!!!