用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