zoukankan      html  css  js  c++  java
  • 构建自己的PHP框架--构建缓存组件(1)

    作为一个框架,我们还没有相应的缓存组件,下面我们就来构建我们的缓存组件。

    先来定义一下接口,在 src 文件夹下创建 cache 文件夹,在cache文件夹下创建 CacheInterface.php 文件,其中定义 Cache 相应的接口,其内容如下:

    <?php
    namespace sfcache;
    
    /**
     * CacheInterface
     * @author Harry Sun <sunguangjun@126.com>
     */
    interface CacheInterface
    {
        /**
         * Builds a normalized cache key from a given key.
         */
        public function buildKey($key);
    
        /**
         * Retrieves a value from cache with a specified key.
         */
        public function get($key);
    
        /**
         * Checks whether a specified key exists in the cache.
         */
        public function exists($key);
    
        /**
         * Retrieves multiple values from cache with the specified keys.
         */
        public function mget($keys);
    
        /**
         * Stores a value identified by a key into cache.
         */
        public function set($key, $value, $duration = 0);
    
        /**
         * Stores multiple items in cache. Each item contains a value identified by a key.
         */
        public function mset($items, $duration = 0);
    
        /**
         * Stores a value identified by a key into cache if the cache does not contain this key.
         * Nothing will be done if the cache already contains the key.
         */
        public function add($key, $value, $duration = 0);
    
        /**
         * Stores multiple items in cache. Each item contains a value identified by a key.
         * If the cache already contains such a key, the existing value and expiration time will be preserved.
         */
        public function madd($items, $duration = 0);
    
        /**
         * Deletes a value with the specified key from cache
         */
        public function delete($key);
    
        /**
         * Deletes all values from cache.
         */
        public function flush();
    }
    

    定义了 buildKey/get/mget/set/mset/exists/add/madd/delete/flush接口,对应功能如下:

    • buildKey:构建真正的 key,避免特殊字符影响实现
    • get:根据 key 获取缓存的值
    • mget:根据 keys 数组获取多个缓存值
    • set:根据 key 设置缓存的值
    • mset:根据数组设置多个缓存值
    • exists:判断 key 是否存在
    • add:如果 key 不存在就设置缓存值,否则返回false
    • madd:根据数组,判断相应的 key 不存在就设置缓存值
    • delete:根据 key 删除一个缓存
    • flush:删除所有的缓存

    实现缓存,可以使用很多方式,比如使用文件、数据库、memcache 以及 Redis 等。

    我们今天先使用文件缓存来实现相应的接口。

    其主要思想就是,每一个 key 都对应一个文件,缓存的内容序列化一下,存入到文件中,取出时再反序列化一下。剩下的基本都是相应的文件操作了。

    在 src/cache 文件夹下创建 FileCache.php 文件,其内容如下:

    <?php
    namespace sfcache;
    
    /**
     * CacheInterface
     * @author Harry Sun <sunguangjun@126.com>
     */
    class FileCache implements CacheInterface
    {
        /**
         * @var string the directory to store cache files.
         * 缓存文件的地址,例如/Users/jun/projects/www/simple-framework/runtime/cache/
         */
        public $cachePath;
        /**
         * Builds a normalized cache key from a given key.
         */
        public function buildKey($key)
        {
            if (!is_string($key)) {
                // 不是字符串就json_encode一把,转成字符串,也可以用其他方法
                $key = json_encode($key);
            }
            return md5($key);
        }
    
        /**
         * Retrieves a value from cache with a specified key.
         */
        public function get($key)
        {
            $key = $this->buildKey($key);
            $cacheFile = $this->cachePath . $key;
            // filemtime用来获取文件的修改时间
            if (@filemtime($cacheFile) > time()) {
                // file_get_contents用来获取文件内容,unserialize用来反序列化文件内容
                return unserialize(@file_get_contents($cacheFile));
            } else {
                return false;
            }
        }
    
        /**
         * Checks whether a specified key exists in the cache.
         */
        public function exists($key)
        {
            $key = $this->buildKey($key);
            $cacheFile = $this->cachePath . $key;
            // 用修改时间标记过期时间,存入时会做相应的处理
            return @filemtime($cacheFile) > time();
        }
    
        /**
         * Retrieves multiple values from cache with the specified keys.
         */
        public function mget($keys)
        {
            $results = [];
            foreach ($keys as $key) {
                $results[$key] = $this->get($key);
            }
            return $results;
        }
    
        /**
         * Stores a value identified by a key into cache.
         */
        public function set($key, $value, $duration = 0)
        {
            $key = $this->buildKey($key);
            $cacheFile = $this->cachePath . $key;
            // serialize用来序列化缓存内容
            $value = serialize($value);
            // file_put_contents用来将序列化之后的内容写入文件,LOCK_EX表示写入时会对文件加锁
            if (@file_put_contents($cacheFile, $value, LOCK_EX) !== false) {
                if ($duration <= 0) {
                    // 不设置过期时间,设置为一年,这是因为用文件的修改时间来做过期时间造成的
                     // redis/memcache 等都不会有这个问题
                    $duration = 31536000; // 1 year
                }
                // touch用来设置修改时间,过期时间为当前时间加上$duration
                return touch($cacheFile, $duration + time());
            } else {
                return false;
            }
        }
    
        /**
         * Stores multiple items in cache. Each item contains a value identified by a key.
         */
        public function mset($items, $duration = 0)
        {
            $failedKeys = [];
            foreach ($items as $key => $value) {
                if ($this->set($key, $value, $duration) === false) {
                    $failedKeys[] = $key;
                }
            }
    
            return $failedKeys;
        }
    
        /**
         * Stores a value identified by a key into cache if the cache does not contain this key.
         */
        public function add($key, $value, $duration = 0)
        {
            //  key不存在,就设置缓存
            if (!$this->exists($key)) {
                return $this->set($key, $value, $duration);
            } else {
                return false;
            }
        }
    
        /**
         * Stores multiple items in cache. Each item contains a value identified by a key.
         */
        public function madd($items, $duration = 0)
        {
            $failedKeys = [];
            foreach ($items as $key => $value) {
                if ($this->add($key, $value, $duration) === false) {
                    $failedKeys[] = $key;
                }
            }
    
            return $failedKeys;
        }
    
        /**
         * Deletes a value with the specified key from cache
         */
        public function delete($key)
        {
            $key = $this->buildKey($key);
            $cacheFile = $this->cachePath . $key;
            // unlink用来删除文件
            return unlink($cacheFile);
        }
    
        /**
         * Deletes all values from cache.
         * Be careful of performing this operation if the cache is shared among multiple applications.
         * @return boolean whether the flush operation was successful.
         */
        public function flush()
        {
            // 打开cache文件所在目录
            $dir = @dir($this->cachePath);
    
            // 列出目录中的所有文件
            while (($file = $dir->read()) !== false) {
                if ($file !== '.' && $file !== '..') {
                    unlink($this->cachePath . $file);
                }
            }
    
            // 关闭目录
            $dir->close();
        }
    }
    

    相关实现的解释都直接写在code中的注释里了。

    然后我们来测试一下我们的缓存组件,首先我们需要添加一下配置文件,在 config 文件夹下创建 cache.php 文件,配置如下内容:

    <?php
    return [
        'class' => 'sfcacheFileCache',
        'cachePath' => SF_PATH . '/runtime/cache/'
    ];
    

    然后在 SiteController.php 中简单使用如下:

        public function actionCache()
        {
            $cache = Sf::createObject('cache');
            $cache->set('test', '我就是测试一下缓存组件');
            $result = $cache->get('test');
            $cache->flush();
            echo $result;
        }
    

    访问 http://localhost/simple-framework/public/index.php?r=site/cache 路径,得到结果如下:

    我就是测试一下缓存组件
    

    这样我们完成了使用文件的缓存组件。

    好了,今天就先到这里。项目内容和博客内容也都会放到Github上,欢迎大家提建议。

    code:https://github.com/CraryPrimitiveMan/simple-framework/tree/0.9

    blog project:https://github.com/CraryPrimitiveMan/create-your-own-php-framework

  • 相关阅读:
    【BZOJ】4636: 蒟蒻的数列
    BZOJ1878 [SDOI2009]HH的项链
    【网络流24题----02】太空飞行计划
    【网络流24题----03】Air Raid最小路径覆盖
    【网络流24题----01】飞行员配对方案问题
    素数判定(米勒测试定理-费马小定理+快速乘)
    一堆模板(丑陋0.0)------数据结构
    丑数(USACO)
    NOI[2001]食物链
    关于Tarjan(2)
  • 原文地址:https://www.cnblogs.com/CraryPrimitiveMan/p/5428224.html
Copyright © 2011-2022 走看看