做为一个框架,咱们尚未相应的缓存组件,下面咱们就来构建咱们的缓存组件。php
先来定义一下接口,在 src 文件夹下建立 cache 文件夹,在cache文件夹下建立 CacheInterface.php 文件,其中定义 Cache 相应的接口,其内容以下:git
<?php namespace sf\cache; /** * 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接口,对应功能以下:github
实现缓存,能够使用不少方式,好比使用文件、数据库、memcache 以及 Redis 等。redis
咱们今天先使用文件缓存来实现相应的接口。数据库
其主要思想就是,每个 key 都对应一个文件,缓存的内容序列化一下,存入到文件中,取出时再反序列化一下。剩下的基本都是相应的文件操做了。json
在 src/cache 文件夹下建立 FileCache.php 文件,其内容以下:数组
<?php namespace sf\cache; /** * 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 文件,配置以下内容:app
<?php return [ 'class' => '\sf\cache\FileCache', '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