上一篇博客中使用文件实现了缓存组件,这一篇我们就使用Redis来实现一下,剩下的如何使用memcache、mysql等去实现缓存我就不一一去做了。

首先我们需要安装一下 redis 和 phpredis 库,phpredis 项目在github上的地址:https://github.com/phpredis/phpredis 。相应的文档也在上面。

先在 src/cache 文件夹下创建 RedisCache.php 文件。在写组件的时候发现我们缺少一个地方去创建一个 Redis 的实例,并且是在创建 cahce 实例之后,返回给Yii::createObject 方法之前。所以我们修改了 src/Sf.php 文件,其 createObject 方法的内容如下:

    public static function createObject($name)
{
$config = require(SF_PATH . "/config/$name.php");
// create instance
$instance = new $config['class']();
unset($config['class']);
// add attributes
foreach ($config as $key => $value) {
$instance->$key = $value;
}
$instance->init();
return $instance;
}

对比之前的代码,不难发现其实只添加了一行 $instance->init(); ,这样我们就可以在 init 方法中去创建相应的 Redis 实例,并保存下来。但这样又会引入一个问题,所有使用 Yii::createObject 创建的实例都必须含有 init 方法(当然你也可以判断有没有这个方法)。那我们就来实现一个基础类 Component ,并规定所有使用 Yii::createObject 创建的实例都集成它,然后再在 Component 中加入 init 方法即可。

为什么选择这种做法,而不是使用判断 init 方法存不存在的方式去解决这个问题,主要是考虑到之后可能还需要对这些类做一些公共的事情,就提前抽出了 Component 类。

Component 类现在很简单,其内容如下:

<?php
namespace sf\base; /**
* Component is the base class for most sf classes.
* @author Harry Sun <sunguangjun@126.com>
*/
class Component
{
/**
* Initializes the component.
* This method is invoked at the end of the constructor after the object is initialized with the
* given configuration.
*/
public function init()
{
}
}

之后再定义一下 Redis 缓存的配置如下:

<?php
return [
'class' => 'sf\cache\RedisCache',
'redis' => [
'host' => 'localhost',
'port' => 6379,
'database' => 0,
// 'password' =>'jun',
// 'options' => [Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP],
]
];

其中 password 和 options 是选填,其它是必填。

剩下的就是相关实现,就不一一细说了,代码如下:

<?php
namespace sf\cache; use Redis;
use Exception;
use sf\base\Component; /**
* CacheInterface
* @author Harry Sun <sunguangjun@126.com>
*/
class RedisCache extends Component implements CacheInterface
{
/**
* @var Redis|array the Redis object or the config of redis
*/
public $redis; public function init()
{
if (is_array($this->redis)) {
extract($this->redis);
$redis = new Redis();
$redis->connect($host, $port);
if (!empty($password)) {
$redis->auth($password);
}
$redis->select($database);
if (!empty($options)) {
call_user_func_array([$redis, 'setOption'], $options);
}
$this->redis = $redis;
}
if (!$this->redis instanceof Redis) {
throw new Exception('Cache::redis must be either a Redis connection instance.');
}
}
/**
* Builds a normalized cache key from a given key.
*/
public function buildKey($key)
{
if (!is_string($key)) {
$key = json_encode($key);
}
return md5($key);
} /**
* Retrieves a value from cache with a specified key.
*/
public function get($key)
{
$key = $this->buildKey($key);
return $this->redis->get($key);
} /**
* Checks whether a specified key exists in the cache.
*/
public function exists($key)
{
$key = $this->buildKey($key);
return $this->redis->exists($key);
} /**
* Retrieves multiple values from cache with the specified keys.
*/
public function mget($keys)
{
for ($index = 0; $index < count($keys); $index++) {
$keys[$index] = $this->buildKey($keys[$index]);
} return $this->redis->mGet($keys);
} /**
* Stores a value identified by a key into cache.
*/
public function set($key, $value, $duration = 0)
{
$key = $this->buildKey($key);
if ($duration !== 0) {
$expire = (int) $duration * 1000;
return $this->redis->set($key, $value, $expire);
} else {
return $this->redis->set($key, $value);
}
} /**
* 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)
{
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);
return $this->redis->delete($key);
} /**
* Deletes all values from cache.
*/
public function flush()
{
return $this->redis->flushDb();
}
}

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

我就是测试一下缓存组件

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

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

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

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

构建自己的PHP框架--构建缓存组件(2)的更多相关文章

  1. 构建自己的PHP框架--构建缓存组件(1)

    作为一个框架,我们还没有相应的缓存组件,下面我们就来构建我们的缓存组件. 先来定义一下接口,在 src 文件夹下创建 cache 文件夹,在cache文件夹下创建 CacheInterface.php ...

  2. 构建自己的PHP框架--构建模版引擎(1)

    前段时间太忙,导致好久都没有更新博客了,今天抽出点时间来写一篇. 其实这个系列的博客很久没有更新了,之前想好好规划一下,再继续写,然后就放下了,今天再捡起来继续更新. 今天我们来说一下,如何构建自己的 ...

  3. 构建自己的PHP框架--构建模版引擎(3)

    之前我们实现了最简单的echo命令的模版替换,就是将{{ $name }}这样一段内容替换成<?php echo $name ?>. 现在我们来说下其他的命令,先来回顾下之前的定义 输出变 ...

  4. 构建自己的PHP框架--构建模版引擎(2)

    自从来到新公司就一直很忙,最近这段时间终于稍微闲了一点,赶紧接着写这个系列,感觉再不写就烂尾了. 之前我们说到,拿到{{ $name }}这样一段内容时,我们只需要将它转化成<?php echo ...

  5. 基于Dubbo框架构建分布式服务(一)

    Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ...

  6. 基于Dubbo框架构建分布式服务

    Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ...

  7. [转载] 基于Dubbo框架构建分布式服务

    转载自http://shiyanjun.cn/archives/1075.html Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务 ...

  8. 教你构建好 SpringBoot + SSM 框架

    来源:Howie_Y https://juejin.im/post/5b53f677f265da0f8f203914 目前最主流的 java web 框架应该是 SSM,而 SSM 框架由于更轻便与灵 ...

  9. 教你十分钟构建好 SpringBoot + SSM 框架

    目前最主流的 java web 框架应该是 SSM,而 SSM 框架由于更轻便与灵活目前受到了许多人的青睐.而 SpringBoot 的轻量化,简化项目配置, 没有 XML 配置要求等优点现在也得到了 ...

随机推荐

  1. [Android] 多重使用Fragment 中的onFragmentInteraction

    新建的一个Fragment,被一个Activity使用,那么这个Activity需要继承一个接口: public class MainActivity extends Activity impleme ...

  2. 有状态Bean和无状态Bean的定义

    有状态会话bean :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”:一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束.即每个用户最初都会得到一个初 ...

  3. HDU---BigZhuGod的粉丝

    Problem Description 真正的粉丝,是不需要题目描述的^_^.   Input 第一行输入数据组数T(1≤T≤100).接下来T行,每行一个有格式的字符串,详见样例,字符串长度不超过1 ...

  4. html5、canvas绘制本地时钟

    效果图: 代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  5. 正在运行的android程序,按home键之后退回到桌面,在次点击程序图标避免再次重新启动程序解决办法

    正在运行的android程序,按home键之后退回到桌面,在次点击程序图标避免再次重新启动程序解决办法 例如:一个android程序包含两个Activity,分别为MainActivity和Other ...

  6. Cocos2d-x游戏引擎实战开发炸弹超人项目教程 全套下载 1至6课

    下载地址: http://pan.baidu.com/s/1b19HN

  7. iOS开发系列--C语言之预处理

    概述 大家都知道一个C程序的运行包括编译和链接两个阶段,其实在编译之前预处理器首先要进行预处理操作,将处理完产生的一个新的源文件进行编译.由于预处理指令是在编译之前就进行了,因此很多时候它要比在程序运 ...

  8. C++的性能C#的产能?! - .Net Native 系列《二》:.NET Native开发流程详解

    之前一文<c++的性能, c#的产能?!鱼和熊掌可以兼得,.NET NATIVE初窥> 获得很多朋友支持和鼓励,也更让我坚定做这项技术的推广者,希望能让更多的朋友了解这项技术,于是先从官方 ...

  9. 今天Windows Azure Live to Code的分享

    今天参加了微软广州的Live to Code,晚上回公司OT写了封报告E-mail,也没让公司今天白出工资给我... 因为没有涉及到公司机密什么的,所以就拿出来跟大家分享一下. 首先要说明的是,在会议 ...

  10. 《Entity Framework 6 Recipes》翻译系列 (4) -----第二章 实体数据建模基础之从已存在的数据库创建模型

    不知道对EF感兴趣的并不多,还是我翻译有问题(如果是,恳请你指正),通过前几篇的反馈,阅读这个系列的人不多.不要这事到最后成了吃不讨好的事就麻烦了,废话就到这里,直奔主题. 2-2 从已存在的数据库创 ...