Parser.php 4.23 KB
<?php

namespace common\components\cachekey;

use Yii;

/**
 * @author wuxiao
 * @date 2016-8-29
 */
class Parser{
    
    //路径
    private $path;
    
    /**
     * 缓存句柄
     * @var type 
     */
    private $cache;
    
    /**
     * 缓存过期时间,秒
     * @var type 
     */
    private $expire = 0;
    
    /**
     * 错误信息
     * @var type 
     */
    static $error;
    
    static function self(){
        static $self;
        if (empty($self)){
            $self = new self;
            
            //初始化缓存句柄
            if (function_exists('apcu_store')){
                $self->cache = Yii::createObject([
                    'class'=>'yii\caching\ApcCache',
                    'useApcu'=>true
                ]);
            }elseif (function_exists('apc_store')){
                $self->cache = Yii::createObject('yii\caching\ApcCache');
            }elseif (function_exists('shm_attach')){
                $self->cache = Yii::createObject('common\components\caching\ShmCache');
            }else{
                $self->cache = Yii::createObject('yii\caching\ArrayCache');
            }
        }
        return $self;
    }
    
    /**
     * 载入路径
     * @param type $path
     * @param type $params
     * @return type
     */
    static function load($path){
        $self = self::self();
        $self->path = $path;
        
        return $self;
    }
    
    /**
     * 获取最终键名
     * @return type
     */
    public function key($params = []){
        
        if (func_num_args() > 1){
            $params = func_get_args();
        }
        $path = $this->path;
        if (is_array($params)){
            ksort($params);
        }
        
        $main_key = 'get'.$path.serialize($params);
        if ($realkey = $this->cache->get($main_key)){
            return $realkey;
        }
        
        $key = 'cacheKey'.$path;
        if (!$cachekey = $this->cache->get($key)){
            $cache = basename($path);
            $dir = dirname($path);
            if (!$cacheMap = $this->read($dir)){
                self::$error = 'cannot read '.$path;
                return;
            }
            if (empty($cacheMap[$cache])){
                self::$error = 'cannot find map key '.$cache;
                return;
            }
            $cachekey = $cacheMap[$cache];
            $this->cache->set($key,$cachekey,$this->expire);
        }
        
        if (count((array)$params) != preg_match_all('/{[^}]+}/',$cachekey)){
            throw new \Exception('Number of arguments not match');
        }
        
        if (is_array($params)){
            if (!is_list($params)){
                $dict = $list = [];
                foreach ($params as $tag=>$value){
                    if (!is_int($tag)){
                        $dict['{'.$tag.'}'] = $value;
                    }else{
                        $list[] = $value;
                    }
                }
                $cachekey = strtr($cachekey,$dict);
                $params = $list;
            }
            
            $realkey = preg_replace('/{[^}]+}/', '%s', $cachekey);
            $realkey = call_user_func_array('sprintf',array($realkey)+$params);
        }else{
            $realkey = preg_replace('/{[^}]+}/', '%s', $cachekey);
            $realkey = sprintf($realkey,$params);
        }
        
        $realkey = $this->addPrefix($realkey);
        $this->cache->set($main_key,$realkey,$this->expire);
        return $realkey;
    }
    
    /**
     * 添加前缀
     * @param type $key
     * @return type
     */
    private function addPrefix($key){
        return strtr(Yii::$app->params['cache_prefix'].':'.$key,array('::'=>':'));
    }
    
    /**
     * 读取文件
     * @param type $path
     * @return boolean
     */
    private function read($path){
        $key = __FUNCTION__.$path;
        if (!$content = $this->cache->get($key)){
            if (!is_readable($file = __DIR__.'/keys/'.$path.'.php')){
                return false;
            }
            $content = include($file);
            $this->cache->set($key,$content,$this->expire);
        }
        return $content;
    }
}
if (!function_exists('is_list')){
    function is_list(array $arr){
        return array_keys($arr) === range(0,count($arr)-1);
    }
}