一种YiiFramework缓存Widget组件的设计

Widget 是 Yii 框架中用于处理页面上通用片段的一种机制, 比如一个同类文章推荐, 虽然数据不一样, 但是功能一样, 这样就可以通过不同的参数提交来提高代码的乃至HTML片段的复用度.
同时 Yii 也自带了缓存机制, 用于实现缓存机制.
而我遇到的实际的情况是, 很多 Widget 需要用到缓存机制, 而如果使用了 Memcache, 单个缓存条目是有1M大小限制的, 因此可能需要使用文件缓存, 那么就需要灵活使用cache方式.
至此就做了如下缓存的Widget.

<?php
/**
 * 自带 Cache 的 Widget
 */
class CacheWidget extends CWidget {

    /**
     * 调用的 Cache Id
     * @var string
     */
    protected $cacheID = 'fcache';

    /**
     * 缓存的 CacheName
     * @var string
     */
    protected $cacheName = '';

    /**
     * 缓存周期
     * @var integer
     */
    protected $duration = 0;

    /**
     * 执行Run
     */
    public final function run() {
        $cacheName = $this->cacheName;
        $duration = $this->duration;
        $cacheID = $this->cacheID;
        if($this->beginCache($cacheName, array(
            'duration'=>$duration,
            'cacheID'=>$cacheID
        ))) {
            $this->runCache();
            $this->endCache();
        }
    }

    /**
     * 实际执行的cache部分
     */
    public function runCache() {
        throw new CExcption('Method `runCache` must be override in class `CacheWidget`.');
    }

}

CacheWidget 继承自 CWidget 继承了 Yii Widget 的大多数功能.

cacheId
确定了可调用的 cache 实例, 在当前的配置下, 我默认使用的 Yii::app()->cache 是 Memcache 而 Yii::app()->fcache 是文件缓存.

cacheName
确定了 cache 的名称, 用于开发者定义 cache 的名字.

duration
确定了 cache 的过期时间, 用于开发者自定义 cache 的过期时间

重写父类 CWidget::run() 方法, 并增加 final 特性. run() 方法是 CWidget 被调用时自动执行的方法, 重写该方法就可以重新定义 run 的执行方式, 定义为 final 是避免开发者继承该类后却习惯性的重写了此方法来实现组件. run()方法完成了Cache的处理过程, 为了便于开发者可以方便的使用此类, 于是对外定义了一个新的方法 runCache() 用于实际执行操作.

再新定义一个 runCache() 方法默认抛出异常, 是强制提醒开发者重写此方法的一种约束.

自此, 一个基于 CWidget 的缓存组件类就开发完成了.
最后附上, CacheWidget 的调用方法:

<?php
class MyWidget extends CacheWidget {

    /**
     * 调用的 Cache Id
     * @var string
     */
    protected $cacheID = 'cache';

    /**
     * 缓存的 CacheName
     * @var string
     */
    protected $cacheName = 'widget.demo';

    /**
     * 缓存周期
     * @var integer
     */
    protected $duration = 3600;

    /**
     * 启动cache调用
     */
    public function runCache() {
        //读取数据
        $demos = DemoModel::model()->findSth();
        $this->render('myWidget', [
            'demos' => $demos,
        ])
    }