做爲一個框架,咱們尚未相應的緩存組件,下面咱們就來構建咱們的緩存組件。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