Yii2如何从前置过滤器获取变量避免重复查询?
在Yii2中实现过滤器间数据共享及控制器获取过滤器值
一、过滤器之间共享查询结果
Yii2的过滤器本质是行为(Behavior),每个过滤器的$owner属性都会指向它所附加的控制器,所以我们可以利用控制器作为中间载体来共享数据,具体步骤如下:
在Filter1中存储查询结果到控制器
在Filter1的beforeAction()方法(过滤器核心执行方法)中,执行SQL查询后,将结果赋值给控制器的自定义属性:<?php namespace app\filters; use yii\base\ActionFilter; use yii\db\Query; class Filter1 extends ActionFilter { public function beforeAction($action) { // 执行你的SQL查询 $queryResult = (new Query()) ->select('*') ->from('your_table') ->where(['status' => 1]) ->all(); // 将结果存储到控制器的自定义属性中 $this->owner->filter1Result = $queryResult; return parent::beforeAction($action); } }在Filter2中读取控制器中的共享数据
因为behaviors中filter1在filter2之前定义,所以Filter2执行时,Filter1的结果已经存在控制器中,直接通过$this->owner获取即可:<?php namespace app\filters; use yii\base\ActionFilter; class Filter2 extends ActionFilter { public function beforeAction($action) { // 从控制器获取Filter1的查询结果 $filter1Data = $this->owner->filter1Result; // 在这里使用$filter1Data做后续逻辑,避免重复查询 if (!empty($filter1Data)) { // 你的业务处理代码 } return parent::beforeAction($action); } }
注意:确保
filter1在behaviors数组中排在filter2前面,Yii2会按照behaviors的定义顺序执行过滤器。
二、控制器中获取过滤器的值
有两种常见方式:
方式1:直接读取控制器的自定义属性
因为过滤器已经将数据存在控制器的属性中,控制器的动作方法里直接调用即可:
<?php namespace app\controllers; use yii\web\Controller; class YourController extends Controller { // 可以提前声明属性,避免IDE警告 public $filter1Result; public function behaviors() { return [ 'filter1' => ['class' => \app\filters\Filter1::className()], 'filter2' => ['class' => \app\filters\Filter2::className()], ]; } public function actionIndex() { // 获取Filter1的查询结果 $data = $this->filter1Result; // 后续业务逻辑 return $this->render('index', ['data' => $data]); } }
方式2:通过行为实例获取(如果过滤器有公开属性)
如果Filter1将查询结果存在自身的公开属性中,也可以通过控制器的behaviors方法获取过滤器实例来读取:
// 修改Filter1,添加公开属性存储结果 class Filter1 extends ActionFilter { public $queryResult; // 公开属性 public function beforeAction($action) { $this->queryResult = (new Query())->...->all(); return parent::beforeAction($action); } } // 控制器中获取 public function actionIndex() { $filter1 = $this->behaviors['filter1']; $data = $filter1->queryResult; // ... }
最佳实践建议
- 为了避免属性名冲突,建议在控制器中定义一个专门的数组属性来存储过滤器共享数据,比如
public $filterShared = [];,然后Filter1中存$this->owner->filterShared['filter1'] = $result;,Filter2中取$this->owner->filterShared['filter1']。 - 如果查询结果比较大,考虑是否需要缓存,进一步提升性能,但这属于额外优化。
内容的提问来源于stack exchange,提问作者chenxinlong
相关产品推荐
相关产品推荐

