上一篇博客中使用文件实现了缓存组件,这一篇我们就使用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. DoD and DoR

    Definition of Ready User Story is defined Acceptance criteria(functional and non-functional requirem ...

  2. 李洪强iOS经典面试题155 - const,static,extern详解(面试必备)

    李洪强iOS经典面试题155 - const,static,extern详解(面试必备) 一.const与宏的区别(面试题): const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽 ...

  3. iphone中input标签会多出一块的解决办法

    -webkit-appearance: none;

  4. FreeMarker中文API手册(完整)

    FreeMarker概述 FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写 FreeMarker被设计用来生成HTML Web页面,特别是基于MVC模式的应用 ...

  5. JSP :运行最简单的 JSP 程序

    160916 1. 代码和显示效果 <%@ page contentType="text/html; charset=GB2312" %> <%@ page im ...

  6. 华为oj 购物单

    这两天断断续续敲完这个(放假的时候比较懒),一次成功有点小激动(●'◡'●)  不过貌似从第一次打开开始计时..... 这道题目很像01背包,我将附件与它们的主件绑定(就是link起来)然后套用动态规 ...

  7. C# winfrom HttpWebRequest 请求获取html网页信息和提交信息

    string result =GetRequest("http://localhost:32163/DuoBao/ajax.aspx", "time=5"); ...

  8. $.load()的用法

    jquery load 事件用法 jquery load 事件用法 如果绑定给window对象,则会在所有内容加载后触发,包括窗口,框架,对象和图像.如果绑定在元素上,则当元素的内容加载完毕后触发. ...

  9. 纯jQuery-添加/修改/删除 标签,属性

    <h1>通过学习<精彩绝伦的jQuery>与W3C,大致了解JQuery的一些方法.</h1> PS:需要有一些前置条件,比如JQuery源代码,比如html就要有 ...

  10. 如何将Eclipse中的项目迁移到Android Studio 中

    如何将Eclipse中的项目迁移到Android Studio 中 如果你之前有用Eclipse做过安卓开发,现在想要把Eclipse中的项目导入到Android Studio的环境中,那么首先要做的 ...