用PHP写一个Redis客户端
自己挖的坑,不仅要自己跳,更要带上别人 —— Jun Feng
Redis客户端的核心就是实现RESP协议,在Redis 2.0中,RESP协议已经成为和Redis服务通信的标准协议。
在编写代码的过程中,只需要完成以下步骤,一个简单的Redis客户端就算是实现了:
- 使用socket连接Redis服务器
- 将命令序列化为RESP协议中的数据结构,并发送给Redis服务器
- 接收Redis服务器返回的数据,并解析成PHP中的数据结构
完成了核心功能,我们就需要对代码进行优化了
面向对象
采用面向对象的思想进行编程好处有许多,就这个项目本身来说,主要是以下几点:
- 对数据进行封装,类似于连接Redis服务器的套接字、连接默认最长等待时间这些数据不应该暴露在外
- 方便用户调用,用户只需实例化一个对象,就可以通过这个对象来使用Redis,简单方便
- 隐藏内部实现的细节,提供统一的接口,编写的Redis客户端是作为一个库来让第三方进行调用的,这需要编写的程序即使内部代码做了修改,对用户却没有影响
魔术方法
巧妙的使用了__call()
这个魔术方法,使得整个代码变得简洁而优雅
class Redis{
public function __call($name, $args)
{
$flatten = '';
array_walk_recursive($args, function ($value) use (&$flatten) {
$flatten .= ' ' . $value;
});
return $name, ' ', $flatten;
}
}
$redis = new Redis();
$redis->set("key", "value"); // set key value
$redis->get("key"); //get key
Redis的命令繁多,如果一一在对象中去定义,不仅麻烦,而且很难维护。这不仅让我感慨动态语言的强大
异常处理
抛出不同的异常类使得异常处理更具有针对性。目前我所想到的会产生异常的场景如下:
- 网络连接过程产生的异常
- 发送非法命令产生的异常
- 对Redis服务器端返回的数据进行解码时产生的异常
懒连接
只有在需要发送命令的时候才会与服务器端建立socket连接,尽力减少资源损耗
流水线技术
通过将命令暂时缓存,从而一次性发送多条命令,达到减少RTT以及IO操作,提高效率的目的
- pipeline_start:开启pipline
- pipeline_end:发送命令,得到命令返回值,关闭pipline
- pipeline_discard:丢弃缓冲区中的命令,关闭pipeline
- pipeline_rollback:清空pipline中缓存的命令
自动加载
代码遵循PSR4规范,可使用通用的自动加载器进行加载,比如说composer中的自动加载器
未来计划
- 对于
SCAN
,SSCAN
,ZSCAN
andHSCAN
等命令,加入PHP迭代器 - 支持Redis发布订阅
- 支持Redis集群
- 支持Redis的主从复制和sentinel机制
下载
使用composer
composer require flagupdown/fjredis
github
https://github.com/flagUpDown/fjredis