Redis.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php namespace Dever\Helper;
  2. use Dever\Debug;
  3. class Redis
  4. {
  5. private static $handle;
  6. private static $expire = 3600;
  7. public static function connect()
  8. {
  9. if (!self::$handle) {
  10. $config = \Dever::config('setting')['redis'] ?? false;
  11. if (!$config) {
  12. \Dever::error('redis error');
  13. }
  14. self::$expire = $config['expire'];
  15. self::$handle = new \Redis;
  16. self::$handle->pconnect($config["host"], $config["port"]);
  17. if (!empty($config['password'])) {
  18. self::$handle->auth($config['password']);
  19. }
  20. self::$handle->setOption(\Redis::OPT_READ_TIMEOUT, -1);
  21. }
  22. return self::$handle;
  23. }
  24. /** -------------------------
  25. * KV 基础操作
  26. * ------------------------ */
  27. public static function get($key)
  28. {
  29. return self::connect()->get($key);
  30. }
  31. public static function set($key, $value, $expire = 0)
  32. {
  33. self::expire($expire);
  34. return self::connect()->set($key, $value, self::$expire);
  35. }
  36. public static function del($key)
  37. {
  38. return self::connect()->del($key);
  39. }
  40. /** -------------------------
  41. * 分布式锁
  42. * ------------------------ */
  43. public static function lock($key, $value, $expire = 0)
  44. {
  45. self::expire($expire);
  46. return self::connect()->set($key, $value, ['NX', 'EX' => $expire]);
  47. }
  48. public static function unlock($key, $value)
  49. {
  50. $script = <<<LUA
  51. if redis.call("get", KEYS[1]) == ARGV[1] then
  52. return redis.call("del", KEYS[1])
  53. else
  54. return 0
  55. end
  56. LUA;
  57. return self::connect()->eval($script, [$key, $value], 1);
  58. }
  59. /** -------------------------
  60. * 自增自减
  61. * ------------------------ */
  62. public static function incr($key, $value = false)
  63. {
  64. return $value ? self::connect()->incrBy($key, $value) : self::connect()->incr($key);
  65. }
  66. public static function decr($key, $value = false)
  67. {
  68. return $value ? self::connect()->decrBy($key, $value) : self::connect()->decr($key);
  69. }
  70. /** -------------------------
  71. * 列表队列
  72. * ------------------------ */
  73. public static function push($key, $value)
  74. {
  75. return self::connect()->lpush($key, $value);
  76. }
  77. public static function pop($key)
  78. {
  79. $data = self::connect()->brPop($key, 10);
  80. if ($data) {
  81. return $data[1] ?? $data;
  82. } else {
  83. $pong = self::connect()->ping();
  84. if ($pong != '+PONG') {
  85. throw new \Exception('Redis ping failure!', 500);
  86. }
  87. usleep(100000);
  88. }
  89. return false;
  90. }
  91. public static function len($key)
  92. {
  93. return self::connect()->lLen($key);
  94. }
  95. /** -------------------------
  96. * Hash 操作
  97. * ------------------------ */
  98. public static function hGet($key, $hkey = false)
  99. {
  100. if ($hkey) {
  101. return self::connect()->hGet($key, $hkey);
  102. }
  103. return self::connect()->hGetAll($key);
  104. }
  105. public static function hDel($key, $hkey)
  106. {
  107. return self::connect()->hDel($key, $hkey);
  108. }
  109. public static function hExists($key, $hkey)
  110. {
  111. return self::connect()->hExists($key, $hkey);
  112. }
  113. public static function hKeys($key)
  114. {
  115. return self::connect()->hKeys($key);
  116. }
  117. public static function hSet($key, $hkey, $value)
  118. {
  119. $res = self::connect()->hSet($key, $hkey, $value);
  120. return $res;
  121. }
  122. public static function hMSet($key, $value)
  123. {
  124. $res = self::connect()->hMSet($key, $value);
  125. return $res;
  126. }
  127. # 原子操作
  128. public static function hOper($key, $field, $amount)
  129. {
  130. $lua = <<<LUA
  131. local balance = redis.call("HGET", KEYS[1], KEYS[2])
  132. local change = tonumber(ARGV[1])
  133. if not balance then
  134. return -1
  135. end
  136. balance = tonumber(balance)
  137. local new_balance = balance + change
  138. if new_balance < 0 then
  139. return 0
  140. end
  141. redis.call("HSET", KEYS[1], KEYS[2], new_balance)
  142. return new_balance
  143. LUA;
  144. return self::connect()->eval($lua, [$key, $field, $amount], 2);
  145. }
  146. public static function oper($key, $amount)
  147. {
  148. $lua = <<<LUA
  149. local balance = redis.call("GET", KEYS[1])
  150. local change = tonumber(ARGV[1])
  151. if not balance then
  152. return -1 --余额未初始化
  153. end
  154. balance = tonumber(balance)
  155. local new_balance = balance + change
  156. if new_balance < 0 then
  157. return 0 --余额不足
  158. end
  159. redis.call("SET", KEYS[1], new_balance)
  160. return new_balance
  161. LUA;
  162. return self::connect()->eval($lua, [$key, $amount], 1);
  163. }
  164. public static function xAdd($key, $col, $value)
  165. {
  166. return self::connect()->xAdd($key, $col, $value);
  167. }
  168. public static function xRead($search, $num, $time)
  169. {
  170. return self::connect()->xRead($search, $num, $time);
  171. }
  172. /** -------------------------
  173. * 关闭连接
  174. * ------------------------ */
  175. public static function close()
  176. {
  177. return self::connect()->close();
  178. }
  179. /** -------------------------
  180. * 设置过期
  181. * ------------------------ */
  182. private static function expire($expire)
  183. {
  184. if ($expire) {
  185. self::$expire = $expire;
  186. }
  187. }
  188. }