构建自己的PHP框架--构建缓存组件(1)
作为一个框架,我们还没有相应的缓存组件,下面我们就来构建我们的缓存组件。
先来定义一下接口,在 src 文件夹下创建 cache 文件夹,在cache文件夹下创建 CacheInterface.php 文件,其中定义 Cache 相应的接口,其内容如下:
<?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接口,对应功能如下:
- 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 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 文件,配置如下内容:
<?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
构建自己的PHP框架--构建缓存组件(1)的更多相关文章
- 构建自己的PHP框架--构建缓存组件(2)
上一篇博客中使用文件实现了缓存组件,这一篇我们就使用Redis来实现一下,剩下的如何使用memcache.mysql等去实现缓存我就不一一去做了. 首先我们需要安装一下 redis 和 phpredi ...
- 构建自己的PHP框架--构建模版引擎(1)
前段时间太忙,导致好久都没有更新博客了,今天抽出点时间来写一篇. 其实这个系列的博客很久没有更新了,之前想好好规划一下,再继续写,然后就放下了,今天再捡起来继续更新. 今天我们来说一下,如何构建自己的 ...
- 构建自己的PHP框架--构建模版引擎(3)
之前我们实现了最简单的echo命令的模版替换,就是将{{ $name }}这样一段内容替换成<?php echo $name ?>. 现在我们来说下其他的命令,先来回顾下之前的定义 输出变 ...
- 构建自己的PHP框架--构建模版引擎(2)
自从来到新公司就一直很忙,最近这段时间终于稍微闲了一点,赶紧接着写这个系列,感觉再不写就烂尾了. 之前我们说到,拿到{{ $name }}这样一段内容时,我们只需要将它转化成<?php echo ...
- 基于Dubbo框架构建分布式服务(一)
Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ...
- 基于Dubbo框架构建分布式服务
Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ...
- [转载] 基于Dubbo框架构建分布式服务
转载自http://shiyanjun.cn/archives/1075.html Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务 ...
- 教你构建好 SpringBoot + SSM 框架
来源:Howie_Y https://juejin.im/post/5b53f677f265da0f8f203914 目前最主流的 java web 框架应该是 SSM,而 SSM 框架由于更轻便与灵 ...
- 教你十分钟构建好 SpringBoot + SSM 框架
目前最主流的 java web 框架应该是 SSM,而 SSM 框架由于更轻便与灵活目前受到了许多人的青睐.而 SpringBoot 的轻量化,简化项目配置, 没有 XML 配置要求等优点现在也得到了 ...
随机推荐
- JavaScript 数组
JavaScript 数组 简介:数组是值的有序集合,JavaScript在同一个数组中可以存放多种类型的元素,而且是长度也是可以动态调整的,可以随着数据增加或减少自动对数组长度做更改. 一:创建数组 ...
- css中关于居中的问题
居中是最常用的一种css格式,不同的居中方法适和不同的环境中,下面总结了几种常用的居中方法,你可以不用它,但是无论你是一个资深前端大牛,还是小小初学者,当你见到它的时候不认识它就是你的不对啦!!! h ...
- [原创]MySQL innodb_rollback_on_timeout参数对锁的影响
环境:Server version: 5.6.21-log MySQL Community Server (GPL) 前提提要: innodb_rollback_on_timeout是 ...
- Xcode 调试技巧
一 NSLog调试 官方文档:Logs an error message to the Apple System Log facility. 即NSLog不是作为普通的debug log的,而是err ...
- 四则运算安卓客户端UI截图(部分)
1.我们组安卓手机客户端UI设计主要由林培文同学负责,界面中用到的素材全部由他一人用PS制作,所以在素材来源上当属原创啦.正因为UI由一个人设计,同时他还得分担少量后台代码的编写,颇多的工作量与人才短 ...
- (转载)H.264码流的RTP封包说明
H.264的NALU,RTP封包说明(转自牛人) 2010-06-30 16:28 H.264 RTP payload 格式 H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) ...
- JAVA第五次作业
import javax.media.; import java.awt.; import java.awt.event.; class MediaPlayer extends Frame imple ...
- MVC学习一:EF
目录 一.EF修改和删除的多种方法 二.标准查询where 三.include 四.skip take 五.反射获取实例属性 六.EF DLL数据访问帮助类 一.EF修改和删除的多种方法 方法1:官方 ...
- 在C#代码中应用Log4Net(三)Log4Net中配置文件的解释
一个完整的配置文件的例子如下所示,这个是”在C#代码中应用Log4Net(二)”中使用的配置文件. <log4net> <!-- 错误日志类--> <logger nam ...
- 巧用transform实现HTML5 video标签视频比例拉伸
前言 原文地址 曾几何时,项目中有碰到视频比例拉伸的需求,但是发现这个看似再普通不过的一个需求,找遍全网至今都没有找到解决方法.因为强制给video标签设置width和height的话只会将video ...