RedisCli.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. declare (strict_types = 1);
  3. namespace library\utils;
  4. // +----------------------------------------------------------------------
  5. // | [ WE CAN DO IT MORE SIMPLE ]
  6. // +----------------------------------------------------------------------
  7. // | Copyright (c) 2018-2020 rights reserved.
  8. // +----------------------------------------------------------------------
  9. // |
  10. // +----------------------------------------------------------------------
  11. // | Date: 2021/2/20 下午1:42
  12. // +----------------------------------------------------------------------
  13. class RedisCli {
  14. // 是否使用 M/S 的读写集群方案
  15. private $_isUseCluster = false;
  16. // Slave 句柄标记
  17. private $_sn = 0;
  18. // 服务器连接句柄
  19. private $_linkHandle = array(
  20. 'master' => null, // 只支持一台 Master
  21. 'slave' => array(), // 可以有多台 Slave
  22. );
  23. /**
  24. * 构造函数
  25. *
  26. * @param boolean $isUseCluster 是否采用 M/S 方案
  27. */
  28. public function __construct($isUseCluster = false) {
  29. $this->_isUseCluster = $isUseCluster;
  30. }
  31. /**
  32. * 连接服务器,注意:这里使用长连接,提高效率,但不会自动关闭
  33. *
  34. * @param array $config Redis服务器配置
  35. * @param boolean $isMaster 当前添加的服务器是否为 Master 服务器
  36. * @return boolean
  37. */
  38. public function connect($config = array('host' => '127.0.0.1', 'port' => 6379), $auth = array(), $isMaster = true) {
  39. // default port
  40. if (!isset($config['port'])) {
  41. $config['port'] = 6379;
  42. }
  43. // 设置 Master 连接
  44. if ($isMaster) {
  45. $this->_linkHandle['master'] = new \Redis();
  46. $ret = $this->_linkHandle['master']->pconnect($config['host'], $config['port']);
  47. if (count($auth) > 0 && !empty($auth[0])) {
  48. if ($this->_linkHandle['master']->auth($auth[0] . ":" . $auth[1]) === false) {
  49. die('Redis PassWord Error');
  50. }
  51. }
  52. } else {
  53. // 多个 Slave 连接
  54. $this->_linkHandle['slave'][$this->_sn] = new Redis();
  55. $ret = $this->_linkHandle['slave'][$this->_sn]->pconnect($config['host'], $config['port']);
  56. if (count($auth) > 0 && !empty($auth[0])) {
  57. if ($this->_linkHandle['master']->auth($auth[0] . ":" . $auth[1]) === false) {
  58. die('Redis PassWord Error');
  59. }
  60. }
  61. ++$this->_sn;
  62. }
  63. return $ret;
  64. }
  65. /**
  66. * 关闭连接
  67. *
  68. * @param int $flag 关闭选择 0:关闭 Master 1:关闭 Slave 2:关闭所有
  69. * @return boolean
  70. */
  71. public function close($flag = 2) {
  72. switch ($flag) {
  73. // 关闭 Master
  74. case 0:
  75. $this->getRedis()->close();
  76. break;
  77. // 关闭 Slave
  78. case 1:
  79. for ($i = 0; $i < $this->_sn; ++$i) {
  80. $this->_linkHandle['slave'][$i]->close();
  81. }
  82. break;
  83. // 关闭所有
  84. case 1:
  85. $this->getRedis()->close();
  86. for ($i = 0; $i < $this->_sn; ++$i) {
  87. $this->_linkHandle['slave'][$i]->close();
  88. }
  89. break;
  90. }
  91. return true;
  92. }
  93. /**
  94. * 得到 Redis 原始对象可以有更多的操作
  95. *
  96. * @param boolean $isMaster 返回服务器的类型 true:返回Master false:返回Slave
  97. * @param boolean $slaveOne 返回的Slave选择 true:负载均衡随机返回一个Slave选择 false:返回所有的Slave选择
  98. * @return redis object
  99. */
  100. public function getRedis($isMaster = true, $slaveOne = true) {
  101. // 只返回 Master
  102. if ($isMaster) {
  103. return $this->_linkHandle['master'];
  104. } else {
  105. return $slaveOne ? $this->_getSlaveRedis() : $this->_linkHandle['slave'];
  106. }
  107. }
  108. /**
  109. * 写缓存
  110. *
  111. * @param string $key 组存KEY
  112. * @param string $value 缓存值
  113. * @param int $expire 过期时间, 0:表示无过期时间
  114. */
  115. public function set($key, $value, $expire = 0) {
  116. // 永不超时
  117. if ($expire == 0) {
  118. $ret = $this->getRedis()->set($key, $value);
  119. } else {
  120. $ret = $this->getRedis()->setex($key, $expire, $value);
  121. }
  122. return $ret;
  123. }
  124. /**
  125. * 读缓存
  126. *
  127. * @param string $key 缓存KEY,支持一次取多个 $key = array('key1','key2')
  128. * @return string || boolean 失败返回 false, 成功返回字符串
  129. */
  130. public function get($key) {
  131. // 是否一次取多个值
  132. $func = is_array($key) ? 'mGet' : 'get';
  133. // 没有使用M/S
  134. if (!$this->_isUseCluster) {
  135. return $this->getRedis()->{$func}($key);
  136. }
  137. // 使用了 M/S
  138. return $this->_getSlaveRedis()->{$func}($key);
  139. }
  140. /*
  141. // magic function
  142. public function __call($name,$arguments){
  143. return call_user_func($name,$arguments);
  144. }
  145. */
  146. /**
  147. * 条件形式设置缓存,如果 key 不存时就设置,存在时设置失败
  148. *
  149. * @param string $key 缓存KEY
  150. * @param string $value 缓存值
  151. * @return boolean
  152. */
  153. public function setnx($key, $value) {
  154. return $this->getRedis()->setnx($key, $value);
  155. }
  156. /**
  157. * 删除缓存
  158. *
  159. * @param string || array $key 缓存KEY,支持单个健:"key1" 或多个健:array('key1','key2')
  160. * @return int 删除的健的数量
  161. */
  162. public function remove($key) {
  163. // $key => "key1" || array('key1','key2')
  164. return $this->getRedis()->delete($key);
  165. }
  166. /**
  167. * 值加加操作,类似 ++$i ,如果 key 不存在时自动设置为 0 后进行加加操作
  168. *
  169. * @param string $key 缓存KEY
  170. * @param int $default 操作时的默认值
  171. * @return int 操作后的值
  172. */
  173. public function incr($key, $default = 1) {
  174. if ($default == 1) {
  175. return $this->getRedis()->incr($key);
  176. } else {
  177. return $this->getRedis()->incrBy($key, $default);
  178. }
  179. }
  180. /**
  181. * 值减减操作,类似 --$i ,如果 key 不存在时自动设置为 0 后进行减减操作
  182. *
  183. * @param string $key 缓存KEY
  184. * @param int $default 操作时的默认值
  185. * @return int 操作后的值
  186. */
  187. public function decr($key, $default = 1) {
  188. if ($default == 1) {
  189. return $this->getRedis()->decr($key);
  190. } else {
  191. return $this->getRedis()->decrBy($key, $default);
  192. }
  193. }
  194. /**
  195. * 添空当前数据库
  196. *
  197. * @return boolean
  198. */
  199. public function clear() {
  200. return $this->getRedis()->flushDB();
  201. }
  202. /* =================== 以下私有方法 =================== */
  203. /**
  204. * 随机 HASH 得到 Redis Slave 服务器句柄
  205. *
  206. * @return redis object
  207. */
  208. private function _getSlaveRedis() {
  209. // 就一台 Slave 机直接返回
  210. if ($this->_sn <= 1) {
  211. return $this->_linkHandle['slave'][0];
  212. }
  213. // 随机 Hash 得到 Slave 的句柄
  214. $hash = $this->_hashId(mt_rand(), $this->_sn);
  215. return $this->_linkHandle['slave'][$hash];
  216. }
  217. /**
  218. * 根据ID得到 hash 后 0~m-1 之间的值
  219. *
  220. * @param string $id
  221. * @param int $m
  222. * @return int
  223. */
  224. private function _hashId($id, $m = 10) {
  225. //把字符串K转换为 0~m-1 之间的一个值作为对应记录的散列地址
  226. $k = md5($id);
  227. $l = strlen($k);
  228. $b = bin2hex($k);
  229. $h = 0;
  230. for ($i = 0; $i < $l; $i++) {
  231. //相加模式HASH
  232. $h += substr($b, $i * 2, 2);
  233. }
  234. $hash = ($h * 1) % $m;
  235. return $hash;
  236. }
  237. /**
  238. * lpush
  239. */
  240. public function lpush($key, $value) {
  241. return $this->getRedis()->lpush($key, $value);
  242. }
  243. /**
  244. * add lpop
  245. */
  246. public function lpop($key) {
  247. return $this->getRedis()->lpop($key);
  248. }
  249. /**
  250. * lrange
  251. */
  252. public function lrange($key, $start, $end) {
  253. return $this->getRedis()->lrange($key, $start, $end);
  254. }
  255. /**
  256. * set hash opeation
  257. */
  258. public function hset($name, $key, $value) {
  259. if (is_array($value)) {
  260. return $this->getRedis()->hset($name, $key, serialize($value));
  261. }
  262. return $this->getRedis()->hset($name, $key, $value);
  263. }
  264. /**
  265. * get hash opeation
  266. */
  267. public function hget($name, $key = null, $serialize = true) {
  268. if ($key) {
  269. $row = $this->getRedis()->hget($name, $key);
  270. if ($row && $serialize) {
  271. unserialize($row);
  272. }
  273. return $row;
  274. }
  275. return $this->getRedis()->hgetAll($name);
  276. }
  277. /**
  278. * delete hash opeation
  279. */
  280. public function hdel($name, $key = null) {
  281. if ($key) {
  282. return $this->getRedis()->hdel($name, $key);
  283. }
  284. return $this->getRedis()->hdel($name);
  285. }
  286. /**
  287. * Transaction start
  288. */
  289. public function multi() {
  290. return $this->getRedis()->multi();
  291. }
  292. /**
  293. * Transaction send
  294. */
  295. public function exec() {
  296. return $this->getRedis()->exec();
  297. }
  298. }