CRedisUtil.php 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  1. <?php
  2. namespace loyalsoft;
  3. //define('Redis_Debug', true); // 调试redis操作
  4. require __DIR__ . '/Predis/Autoloader.php';
  5. \Predis\Autoloader::register();
  6. /**
  7. * redis操作封装,
  8. * 关于阿里云redis的支持命令和未开放命令见:
  9. * https://docs.aliyun.com/?spm=5176.7630237.9.3.WfKF0A#/pub/kvstore/quick-start/kvstore-redis-command
  10. * 腾讯云支持的命令:
  11. * https://www.qcloud.com/doc/product/239/%E4%BD%BF%E7%94%A8%E9%99%90%E5%88%B6
  12. * redis相关命令说明见:http://redisdoc.com/
  13. *
  14. * 支持命令集接口见: /phpRedisAdmin/predis/src/ClientInterface.php
  15. * @version <br/>
  16. * 1.0.4 取消公共基类CMemBase,后面可能不太会用到memcache(d)了. gwang 2020年11月23日
  17. * 1.0.3 扩展list相关api的操作方法, 针对values统一做json编解码处理.
  18. * 整理其他数据结构的操作方法, normal/hash/list api内部做json编解码处理,
  19. * set/zset value 默认不做json编解码处理, 针对set/zset的value,不推荐写入太大或复杂的数据.
  20. * gwang 2017年4月28日 <br/>
  21. * 1.0.2 扩充特有数据结构的操作方法, gwang 2016.4.21 <br/>
  22. * 1.0.1 扩充了事务的使用方法.开发竞争类业务,圣树争夺战, gwang 2016.3.21 <br/>
  23. * 1.0.0 pguan,基础功能, 方法与memcache看齐. <br/>
  24. */
  25. class CRedisUtil {
  26. // public $keyDic = null;
  27. /**
  28. *
  29. * @var ClientInterface
  30. */
  31. public $redis = null;
  32. /**
  33. * 自动回收
  34. */
  35. function __destruct() {
  36. $this->close();
  37. }
  38. private static function debug() {
  39. if (defined('Redis_Debug') && Redis_Debug) {
  40. DebugHelper::debug(DebugHelper::get_call_stack());
  41. }
  42. }
  43. // <editor-fold defaultstate="collapsed" desc=" 实现CMemBase操作接口">
  44. /**
  45. * 添加一个值
  46. * @param string $key
  47. * @param string $value
  48. * @param int $ts=0 此值无效
  49. * @return true 成功, false 失败,此key已经存在
  50. */
  51. public function add($key, $value, $ts = 0) {
  52. self::debug();
  53. return $this->setnx($key, JsonUtil::encode($value));
  54. }
  55. /**
  56. * 复制一个变量到另一个key
  57. * @param string $surKey 源数据的key
  58. * @param string $desKey 目的数据的key
  59. */
  60. public function copy($surKey, $desKey) {
  61. self::debug();
  62. return $this->set($desKey, $this->get($surKey));
  63. }
  64. /**
  65. * 一次取多个值
  66. * @param array(string) $keys
  67. * @return array
  68. */
  69. public function getMulti($keys) {
  70. self::debug();
  71. // var_dump($keys);
  72. return $this->mget($keys);
  73. }
  74. /**
  75. * 设置多个值
  76. * @param dic $dict [{"key":value},{"key":value},....]
  77. * @param int $expireTs=0 此值无效
  78. * @return true 永远成功
  79. */
  80. public function setMutlti($dict, $expireTs = 0) {
  81. self::debug();
  82. $params = array();
  83. foreach ($dict as $key => $val) {
  84. $params[$key] = is_string($val) ? $val : JsonUtil::encode($val);
  85. }
  86. if (count($params) <= 0) {
  87. return TRUE;
  88. }
  89. $this->mset($params);
  90. return true;
  91. }
  92. /**
  93. * 替换某个值
  94. * @param string $key
  95. * @param string $value
  96. * @param int $ts
  97. * @return boolean true 成功,false 失败
  98. */
  99. public function replace($key, $value, $ts = 0) {
  100. self::debug();
  101. $ret = $this->redis->setex($key, $value, $ts);
  102. if (strtolower($ret) == "ok") {
  103. return true;
  104. }
  105. $this->logErr("replace" . $ret);
  106. return false;
  107. }
  108. /**
  109. * 不经过jsonencode直接存储
  110. * @deprecated since version 20160413113950 经过自己考察json_encode对数据的影响并不存在
  111. * @param type $key
  112. * @return any
  113. */
  114. public function getWithoutJson($key) {
  115. self::debug();
  116. return $this->redis->get($key);
  117. }
  118. /**
  119. * 不经过jsondecode直接返回
  120. * @deprecated since version 20160413113950 经过自己考察json_encode对数据的影响并不存在
  121. * @param string $key
  122. * @param string $value
  123. * @param int $ts
  124. * @return boolean
  125. */
  126. public function setWithoutJson($key, $value, $ts = 0) {
  127. self::debug();
  128. $ret = $this->redis->set($key, $value, $ts);
  129. if (strtolower($ret) == "ok") {
  130. return true;
  131. }
  132. $this->logErr("set" . $ret);
  133. return false;
  134. }
  135. /**
  136. * 输出日志
  137. * @param mixed $msg
  138. */
  139. private function logErr($msg) {
  140. CLog::err($msg, "Redis Err:");
  141. }
  142. /**
  143. * 连接
  144. * @param string $host
  145. * @param string $port
  146. * @param string $pwd
  147. * @return \CRedisUtil
  148. */
  149. public function conn($host, $port, $pwd = "") {
  150. // DebugHelper::print_stack_trace();
  151. $this->redis = new \Predis\Client(array(
  152. 'scheme' => 'tcp',
  153. 'host' => $host,
  154. 'port' => $port,
  155. 'password' => $pwd,
  156. ));
  157. // $this->keyDic = new \stdClass();
  158. return $this;
  159. }
  160. /**
  161. * 关闭连接
  162. */
  163. public function close() {
  164. $this->redis->quit();
  165. }
  166. /**
  167. * 获取指定键值
  168. * @param string $key
  169. * @return any json_decode($result)
  170. */
  171. public function get($key) {
  172. self::debug();
  173. $result = $this->redis->get($key);
  174. if (!$result || $result == "" || $result == null) {
  175. return null;
  176. }
  177. // $this->keyDic->$key = $result;
  178. return JsonUtil::decode($result);
  179. }
  180. /**
  181. * 将字符串值 $val 关联到 key
  182. * @param string $key
  183. * @param any $value
  184. * @param int $ts default(0) 过期时间(单位秒)
  185. * @return boolean 成功true,失败false
  186. */
  187. public function set($key, $value, $ts = 0) {
  188. self::debug();
  189. if ($value === null || $value === "") { # 这里必须用全等符号
  190. return false;
  191. }
  192. if (is_string($value)) { # 使用json序列化后存储
  193. $val = $value;
  194. } else {
  195. $val = JsonUtil::encode($value);
  196. }
  197. if ($ts > 0) { # 将会设置TTL 到期删除 ps: replaced by gwang 增加过期时间
  198. $ret = $this->redis->setex($key, $ts, $val);
  199. } else { # 0:永不过期,如果原来有TTL将会清除TTL.
  200. $ret = $this->redis->set($key, $val);
  201. }
  202. if ("OK" != $ret) {
  203. $this->logErr("Set:" . $ret);
  204. return false;
  205. }
  206. return true;
  207. }
  208. // /**
  209. // * 安全的写入操作
  210. // * @deprecated since version 1.0 云平台暂时不支持
  211. // * @param string $key
  212. // * @param any $value
  213. // * @return boolean 成功true,失败false
  214. // */
  215. // public function cas($key, $value, $ts = 0) {
  216. // if (false) { # ps. 各云平台皆不支持eval方法执行lua脚本.等开放支持的时候才是真正支持cas的时候
  217. // $castoken = $this->keyDic->$key;
  218. //# # 定义一段脚本
  219. // $script = <<<casscript
  220. //if redis.call("get",KEYS[1]) == "$castoken"
  221. //then
  222. // return redis.call("set",KEYS[1],ARGV[1])
  223. //else
  224. // return 0
  225. //end
  226. //casscript;
  227. // $ret = $this->redis->eval($script, 1, $key, $value); # redis 执行lua脚本
  228. // if (0 == $ret) {
  229. // return false;
  230. // }
  231. // return true;
  232. // }
  233. //
  234. // // 非线程安全,原因见下
  235. // return $this->set($key, $value, $ts);
  236. // }
  237. /**
  238. * 删除一个或多个指定键值
  239. * @param string $keys
  240. * @return int 删除键的个数
  241. */
  242. public function delete($key) {
  243. self::debug();
  244. $infos = array();
  245. array_push($infos, $key);
  246. return $this->redis->del($infos);
  247. }
  248. // </editor-fold>
  249. //
  250. // <editor-fold defaultstate="collapsed" desc=" normal 普通对象操作 mget/mset">
  251. /**
  252. * 返回所有(一个或多个)给定 key 的值
  253. * 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。
  254. * @param array $keys
  255. * @return array 一个包含所有给定 key 的值的列表
  256. */
  257. private function mget($keys) {
  258. // self::debug();
  259. $ret = array();
  260. if (count($keys)) {
  261. $ctx = $this->redis->mget($keys);
  262. $mval = count($ctx);
  263. for ($i = 0; $i < $mval; $i++) {
  264. $ret[] = JsonUtil::decode($ctx[$i]);
  265. }
  266. }
  267. return $ret;
  268. }
  269. /**
  270. * Add函数拥有相同效果 \n
  271. * 将 key 的值设为 value ,当且仅当 key 不存在。
  272. * 若给定的 key 已经存在,则不做任何动作。
  273. * @param type $key
  274. * @param type $val
  275. * @return boolean 成功true,失败false
  276. */
  277. private function setnx($key, $val) {
  278. self::debug();
  279. $ret = $this->redis->setnx($key, $val);
  280. // 成功返回1, 失败返回0
  281. if (1 == $ret) {
  282. return true;
  283. } else {
  284. $this->logErr("setnx:" . $ret . "(值已存在)");
  285. }
  286. return false;
  287. }
  288. /**
  289. * 同时设置一个或多个 key-value 对
  290. * 如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值
  291. * @param array $dict
  292. * @return mixed
  293. */
  294. private function mset($dict) {
  295. self::debug();
  296. return $this->redis->mset($dict);
  297. }
  298. /**
  299. * 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在
  300. * 即使只有一个给定 key 已存在, MSETNX 也会拒绝执行所有给定 key 的设置操作
  301. *
  302. * @param array $dict
  303. * @return int
  304. */
  305. public function msetnx($dict) {
  306. self::debug();
  307. $ret = $this->redis->msetnx($dict);
  308. return $ret == 1;
  309. }
  310. /**
  311. * 检测指定键值是否存在
  312. * @param type $key
  313. * @return boolean true 存在, false 不存在
  314. */
  315. public function exists($key) {
  316. self::debug();
  317. return $this->redis->exists($key) == 1;
  318. }
  319. /**
  320. * 将 key 中储存的数字值增一
  321. * 如果 key 不存在,那么 key 的值会先被初始化为 0
  322. * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误
  323. * 本操作的值限制在 64 位(bit)有符号数字表示之内
  324. * @param type $key
  325. * @return int 执行 INCR 命令之后 key 的值
  326. */
  327. public function increment($key) {
  328. self::debug();
  329. return $this->redis->incr($key);
  330. }
  331. /**
  332. * 将 key 中储存的数字值增加 一个int值
  333. * 如果 key 不存在,那么 key 的值会先被初始化为 0
  334. * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误
  335. * 本操作的值限制在 64 位(bit)有符号数字表示之内
  336. * @param string $key
  337. * @param int $i 增加的值
  338. * @return int 执行 INCR 命令之后 key 的值
  339. */
  340. public function incrby($key, $i) {
  341. self::debug();
  342. return $this->redis->incrby($key, $i);
  343. }
  344. // </editor-fold>
  345. //
  346. //======================== 以下部分 added by gwang at 2016-4-14 15:17:25 =================
  347. // <editor-fold defaultstate="collapsed" desc=" 辅助函数 ">
  348. /**
  349. * Server功能,看服务器是否连通
  350. * @return boolean true连通正常
  351. */
  352. public function ping() {
  353. $ret = $this->redis->ping();
  354. if ($ret == "PONG") {
  355. return true;
  356. }
  357. $this->logErr("ping:" . $ret);
  358. return false;
  359. }
  360. /**
  361. * 对数组进行json编码
  362. * @param array $values
  363. * @return array
  364. */
  365. static private function json_encode_arr($values) {
  366. $arr = array();
  367. if (is_array($values)) {
  368. $arr = array_map(function ($v) {
  369. return JsonUtil::encode($v);
  370. }, $values);
  371. } else {
  372. $arr[] = JsonUtil::encode($values);
  373. }
  374. return $arr;
  375. }
  376. /**
  377. * 对数组进行json解码
  378. * @param array $values
  379. * @return array
  380. */
  381. static private function json_decode_arr(array $values) {
  382. $arr = array();
  383. if (is_array($values)) {
  384. $arr = array_map(function ($v) {
  385. return JsonUtil::decode($v);
  386. }, $values);
  387. } else {
  388. $arr[] = JsonUtil::decode($values);
  389. }
  390. return $arr;
  391. }
  392. // </editor-fold>
  393. //
  394. // <editor-fold defaultstate="collapsed" desc=" 事务操作 ">
  395. /**
  396. * 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
  397. * @param string $key
  398. */
  399. public function watch($key) {
  400. $this->redis->watch($key);
  401. }
  402. /**
  403. * 取消监视
  404. */
  405. public function unwatch() {
  406. $this->redis->unwatch();
  407. }
  408. /**
  409. * 开启事务
  410. */
  411. public function multi() {
  412. $this->redis->multi();
  413. }
  414. /**
  415. * 执行事务
  416. * @return type 事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil 。
  417. */
  418. public function exec() {
  419. return $this->redis->exec();
  420. }
  421. // </editor-fold>
  422. //
  423. // == ↓ 下面是Redis独有的数据类型操作 ↓ ==
  424. //
  425. // <editor-fold defaultstate="collapsed" desc=" set 集合操作 ">
  426. /**
  427. * 集合(set) - 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
  428. * 集合不存在时将会创建集合
  429. * @param string $key
  430. * @param string[] $members (mixed is ok, i will transmit it.)
  431. * @return int
  432. * @expectedException type not set error
  433. */
  434. public function sadd($key, $members) {
  435. self::debug();
  436. if (!is_array($members)) { # 防御: 参数不为数组
  437. if (!is_string($members)) { # 防御: 参数不为字符串
  438. $members = JsonUtil::encode($members);
  439. }
  440. $members = array($members); # 转为字符串数组
  441. }
  442. return $this->redis->sadd($key, $members);
  443. }
  444. /**
  445. * 集合(set) - 将一个或多个 member 元素从集合 key 当中移除
  446. * 集合不存在时将会创建集合
  447. * @param string $key
  448. * @param string[] $members
  449. * @return int
  450. * @expectedException type not set error
  451. */
  452. public function sremove($key, $members) {
  453. self::debug();
  454. return $this->redis->srem($key, $members);
  455. }
  456. /**
  457. * 集合(set) - 返回集合 key 的基数(集合中元素的数量)。
  458. * @param strig $key
  459. * @return int
  460. */
  461. public function scard($key) {
  462. self::debug();
  463. return $this->redis->scard($key);
  464. }
  465. /**
  466. * 集合(set) - 等效于scard: 返回集合 key 的基数(集合中元素的数量)。
  467. * @param string $key
  468. * @return int
  469. *
  470. */
  471. public function slen($key) {
  472. self::debug();
  473. return $this->scard($key);
  474. }
  475. /**
  476. * 集合(set) - 判断某个元素是否属于集合
  477. * @param string $key
  478. * @param string $member
  479. * @return bool
  480. */
  481. public function sismember($key, $member) {
  482. self::debug();
  483. return $this->redis->sismember($key, $member) == 1;
  484. }
  485. /**
  486. * 集合(set) - 返回集合 key 中的所有成员。
  487. * @param type $key
  488. * @return array 不存在的key视为空集合
  489. */
  490. public function smembers($key) {
  491. self::debug();
  492. return $this->redis->smembers($key);
  493. }
  494. /**
  495. * 集合(set) - 如果命令执行时,只提供了 key 参数,那么返回集合中的10个随机元素。
  496. * 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。
  497. * 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
  498. * @param string $key
  499. * @param int $count =10
  500. * @return array
  501. */
  502. public function srandmember($key, $count = 10) {
  503. self::debug();
  504. return $this->redis->srandmember($key, $count);
  505. }
  506. // </editor-fold>
  507. //
  508. // <editor-fold defaultstate="collapsed" desc=" hash 哈希表操作 ">
  509. /**
  510. * 哈希表 - 删除 字段
  511. * @param string $key
  512. * @param array $fields
  513. * @return int 删除的字段的数量
  514. */
  515. public function hdel($key, $fields) {
  516. self::debug();
  517. return $this->redis->hdel($key, $fields);
  518. }
  519. /**
  520. * 哈希表 - 判断field是否存在
  521. * @param string $key
  522. * @param string $field
  523. * @return boolean true=存在,false 找不到
  524. */
  525. public function hexists($key, $field) {
  526. self::debug();
  527. return $this->redis->hexists($key, $field) == 1;
  528. }
  529. /**
  530. * 哈希表 - 获取字段
  531. * @param string $key
  532. * @param string $field 字段名
  533. * @return mixed json_decoded object
  534. */
  535. public function hget($key, $field) {
  536. self::debug();
  537. $ret = $this->redis->hget($key, $field);
  538. return JsonUtil::decode($ret);
  539. }
  540. /**
  541. * 哈希表 - 获取所有字段
  542. * @param string $key
  543. * @return stdclass/associate_array (适用箭头取变量写法)
  544. */
  545. public function hgetall($key) {
  546. self::debug();
  547. $ret = ArrayInit();
  548. $arr = $this->redis->hgetall($key);
  549. foreach ($arr as $k => $v) {
  550. $ret[$k] = JsonUtil::decode($v);
  551. }
  552. // 转为关联数组({})再返回, 方便代码中使用箭头写法
  553. return JsonUtil::decode(JsonUtil::encode($ret));
  554. }
  555. /**
  556. * 哈希表 - 获取表中字段数量
  557. * @param string $key
  558. * @return int
  559. */
  560. public function hlen($key) {
  561. self::debug();
  562. return $this->redis->hlen($key);
  563. }
  564. /**
  565. * 哈希表 - 同时获取多个字段
  566. * @param string $key
  567. * @param array $fields
  568. * @return Array
  569. */
  570. public function hmget($key, $fields) {
  571. self::debug();
  572. $ret = ArrayInit();
  573. if (is_array($fields) && count($fields) > 0) {
  574. $arr = $this->redis->hmget($key, $fields);
  575. foreach ($arr as $k => $v) {
  576. $ret[$k] = JsonUtil::decode($v);
  577. }
  578. }
  579. // 转为关联数组({})再返回, 方便代码中使用箭头写法
  580. return JsonUtil::decode(JsonUtil::encode($ret));
  581. }
  582. /**
  583. * 哈希表 - 同时设置多个字段的值
  584. * @param string $key
  585. * @param assoc_array $dictionary
  586. * @return boolean true成功
  587. */
  588. public function hmset($key, $dictionary) {
  589. self::debug();
  590. $newdic = ArrayInit();
  591. foreach ($dictionary as $k => $v) {
  592. $newdic[$k] = JsonUtil::encode($v);
  593. }
  594. $ret = $this->redis->hmset($key, $newdic);
  595. if (strtolower($ret) == 'ok') {
  596. return true;
  597. }
  598. return false;
  599. }
  600. /**
  601. * 哈希表 - 设置或新建一个字段的值
  602. * @param string $key
  603. * @param string $field
  604. * @param $mixed $value
  605. * @return int 0 覆盖旧值, 1 新建字段
  606. */
  607. public function hset($key, $field, $value) {
  608. self::debug();
  609. return $this->redis->hset($key, $field, JsonUtil::encode($value));
  610. }
  611. /**
  612. * 哈希表 - 增加一个新的field,已经存在则放弃操作返回false
  613. * @param string $key
  614. * @param string $field
  615. * @param string $value
  616. * @return boolean true成功
  617. */
  618. public function hsetnx($key, $field, $value) {
  619. self::debug();
  620. return $this->redis->hsetnx($key, $field, JsonUtil::encode($value)) == 1;
  621. }
  622. /**
  623. * 哈希表 - 按字段赠加 int值
  624. * @param string $key
  625. * @param string $field
  626. * @param int $increment
  627. * @return int
  628. */
  629. public function hincrby($key, $field, $increment) {
  630. self::debug();
  631. return $this->redis->hincrby($key, $field, $increment);
  632. }
  633. /**
  634. * 哈希表 - 按字段增加 float值
  635. * @param string $key
  636. * @param string $field
  637. * @param string $increment float值用string
  638. * @return string 用string存float值
  639. */
  640. public function hincrbyfloat($key, $field, $increment) {
  641. self::debug();
  642. return $this->redis->hincrbyfloat($key, $field, $increment);
  643. }
  644. /**
  645. * @param string $key
  646. * @return array
  647. */
  648. public function hkeys($key) {
  649. self::debug();
  650. return $this->redis->hkeys($key);
  651. }
  652. // * @method array hscan($key, $cursor, array $options = null)
  653. // * @method array hvals($key)
  654. // </editor-fold>
  655. //
  656. // <editor-fold defaultstate="collapsed" desc=" list 链表操作 ">
  657. //
  658. // <editor-fold defaultstate="collapsed" desc=" 阻塞的链表操作 ">
  659. /**
  660. * 链表 - 阻塞弹出, 当列表中没有元素的时候,命令会阻塞,直到等待超时或者有元素被添加到列表中.
  661. * @param array $keys 可以指定多个数组
  662. * @param int $timeout
  663. * @return array
  664. */
  665. public function blpop(array $keys, $timeout) {
  666. self::debug();
  667. $arr = $this->redis->blpop($keys, $timeout);
  668. $arr[1] = JsonUtil::decode($arr[1]); // 对value进行解包
  669. return $arr;
  670. }
  671. /**
  672. * 链表 - 阻塞队尾弹出, 当列表中没有元素的时候,命令会阻塞,直到等待超时或者有元素被添加到列表中.
  673. * @return array
  674. */
  675. public function brpop(array $keys, $timeout) {
  676. self::debug();
  677. $arr = $this->redis->brpop($keys, $timeout);
  678. $arr[1] = JsonUtil::decode($arr[1]);
  679. return $arr;
  680. }
  681. /**
  682. * 链表 - 阻塞版的 队尾弹出插入到队首. 本操作是原子的.
  683. *
  684. * @return array 假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。
  685. * 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。
  686. */
  687. public function brpoplpush($source, $destination, $timeout) {
  688. self::debug();
  689. $arr = $this->redis > brpoplpush($source, $destination, $timeout);
  690. $arr[0] = JsonUtil::decode($arr[0]);
  691. return $arr;
  692. }
  693. // </editor-fold>
  694. //
  695. /**
  696. * 链表 - 返回下标为index的元素
  697. * @return string
  698. */
  699. public function lindex($key, $index) {
  700. self::debug();
  701. $a = $this->redis->lindex($key, $index);
  702. return JsonUtil::decode($a);
  703. }
  704. /**
  705. * 链表 - 返回 链表key的长度
  706. * @return int
  707. * @param type $key
  708. */
  709. public function llen($key) {
  710. self::debug();
  711. return $this->redis->llen($key);
  712. }
  713. /**
  714. * 链表 - 移除并返回链表的队首元素.
  715. * @return string
  716. * @param type $key
  717. */
  718. public function lpop($key) {
  719. self::debug();
  720. $a = $this->redis->lpop($key);
  721. return JsonUtil::decode($a);
  722. }
  723. /**
  724. * 链表 - 向链表插入一个或多个值,链表不存在时创建链表并插入元素
  725. * @return int key存在却不是链表类型时返回一个错误.
  726. * @param type $key
  727. * @param array $values
  728. */
  729. public function lpush($key, $values) {
  730. self::debug();
  731. $arr = self::json_encode_arr($values);
  732. return $this->redis->lpush($key, $arr);
  733. }
  734. /**
  735. * 链表 - 取链表中指定下标区间的元素
  736. * @return array
  737. * @param string $key
  738. * @param int $start
  739. * @param int $stop
  740. */
  741. public function lrange($key, $start, $stop) {
  742. self::debug();
  743. $values = $this->redis->lrange($key, $start, $stop);
  744. return self::json_decode_arr($values);
  745. }
  746. /**
  747. * 链表 - 移除链表中 count 个值为 value的元素.
  748. * @return int
  749. * @param string $key
  750. * @param int $count
  751. * @param string $value
  752. */
  753. public function lrem($key, $count, $value) {
  754. self::debug();
  755. return $this->redis->lrem($key, $count, JsonUtil::encode($value));
  756. }
  757. /**
  758. * 链表 - 将链表中下标为index的 元素设置为value
  759. * @return mixed
  760. *
  761. * @param type $key
  762. * @param type $index
  763. * @param type $value
  764. */
  765. public function lset($key, $index, $value) {
  766. self::debug();
  767. return $this->redis->lset($key, $index, JsonUtil::encode($value));
  768. }
  769. /**
  770. * 链表 - 对链表进行修剪, 让链表只保留指定下标区间的元素,其余元素删除
  771. * @return bool true 成功, false 失败
  772. * @param string $key
  773. * @param int $start
  774. * @param int $stop
  775. */
  776. public function ltrim($key, $start, $stop) {
  777. self::debug();
  778. // return mixed: ok or fails
  779. $ret = $this->redis->ltrim($key, $start, $stop);
  780. if (strtolower($ret) == 'ok') {
  781. return true;
  782. }
  783. return false;
  784. }
  785. /**
  786. * 链表 - 从链表右侧(尾部)弹出一个元素,并返回该元素
  787. * @param string $key
  788. * @return string 列表的尾元素。当 key 不存在时,返回 nil
  789. */
  790. public function rpop($key) {
  791. self::debug();
  792. return JsonUtil::decode($this->redis->rpop($key));
  793. }
  794. /**
  795. * 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
  796. * @param string $key
  797. * @param array $values
  798. * @return int
  799. */
  800. public function rpush($key, array $values) {
  801. self::debug();
  802. $arr = self::json_encode_arr($values);
  803. return $this->redis->rpush($key, $arr);
  804. }
  805. //
  806. // /**
  807. // * 链表 - 向链表中插入一个或多个值,链表不存在时,什么也不做.
  808. // * @return int
  809. // * @param type $key
  810. // * @param type $value
  811. // */
  812. // public function lpushx($key, $value)
  813. // {
  814. // return $this->redis->lpushx($key, $value);
  815. // }
  816. // /**
  817. // * 链表 - 将值 value 插入到链表 key 中 , 位于pivot之前或之后
  818. // * @return int -1:未找到pivot, 0:链表为空或者不存在.
  819. // *
  820. // * @param string $key 链表名称
  821. // * @param string $whence after/before pivot之前或之后
  822. // * @param string $pivot 插入pivot之前或之后
  823. // * @param string $value 要插入的value
  824. // */
  825. // public function linsert($key, $whence, $pivot, $value)
  826. // {
  827. // $this->redis->linsert($key, $whence, $pivot, $value);
  828. // }
  829. // /**
  830. // * 在一个原子时间内,执行以下两个动作
  831. // * 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
  832. // * 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素.
  833. // * @return string
  834. // */
  835. // public function rpoplpush($source, $destination)
  836. // {
  837. // throw new Exception("un implemented now!");
  838. // }
  839. // /**
  840. // * 将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表。
  841. // * 和 RPUSH 命令相反,当 key 不存在时, RPUSHX 命令什么也不做。
  842. // * @param type $key
  843. // * @param type $value
  844. // * @return int
  845. // */
  846. // public function rpushx($key, $value)
  847. // {
  848. // throw new Exception("un implemented now!");
  849. // }
  850. // </editor-fold>
  851. //
  852. // <editor-fold defaultstate="collapsed" desc=" zset 有序集合 ">
  853. /**
  854. * 有序集合 - 添加或更新元素 对于zset类型不建议写入太长, 太复杂的value
  855. * @param string $key
  856. * @param array $membersAndScoresDictionary array( 'value'=>score,'value'=>score,...), score可以是int或float
  857. * @return int 新增元素数量,不包含更新的元素
  858. */
  859. public function zadd($key, $membersAndScoresDictionary) {
  860. self::debug();
  861. return $this->redis->zadd($key, $membersAndScoresDictionary);
  862. }
  863. /**
  864. * 有序集合 - 给某个元素增加积分
  865. * @param string $key
  866. * @param string $member
  867. * @param int $increment
  868. * @return string
  869. */
  870. public function zincrby($key, $member, $increment = 1) {
  871. self::debug();
  872. return $this->redis->zincrby($key, $increment, $member);
  873. }
  874. /**
  875. * 有序集合 - 元素数量
  876. * @param string $key
  877. * @return int
  878. */
  879. public function zlen($key) {
  880. self::debug();
  881. return $this->redis->zcard($key);
  882. }
  883. /**
  884. * 有序集合 - 统计某区间元素数量
  885. * @param string $key
  886. * @param int/float $min 最低分
  887. * @param int/float $max 最高分
  888. * @return int
  889. */
  890. public function zcount($key, $min, $max) {
  891. self::debug();
  892. return $this->redis->zcount($key, $min, $max);
  893. }
  894. /**
  895. * 有序集合 - 获取集合指定区间内的成员, 第一个成员从0开始
  896. * @param string $key
  897. * @param int $start
  898. * @param int $stop Ps.以 -1 表示最后一个成员, -2 表示倒数第二个成员
  899. * @param boolean $withScore 返回值中是否带score字段
  900. * @return array (index=>member) or assoc_array (member=>score)
  901. */
  902. public function zrange($key, $start, $stop, $withScore = false) {
  903. self::debug();
  904. if ($withScore) {
  905. return $this->redis->zrange($key, $start, $stop, 'WITHSCORES');
  906. } else {
  907. return $this->redis->zrange($key, $start, $stop);
  908. }
  909. if ($withScore) {
  910. $ret = $this->redis->zrange($key, $start, $stop, 'WITHSCORES');
  911. DebugHelper::var_dump($ret);
  912. $ma = count($ret);
  913. $arr = array();
  914. for ($i = 0; $i < $ma; $i += 2) {
  915. $arr[$ret[$i]] = $ret[$i + 1];
  916. }
  917. return $arr;
  918. } else {
  919. $ret = $this->redis->zrange($key, $start, $stop);
  920. DebugHelper::var_dump($ret);
  921. return $ret;
  922. }
  923. }
  924. /**
  925. *
  926. * 有序集合 - 获取集合倒序之后,指定区间内的成员, 第一个成员从0开始
  927. * @param string $key
  928. * @param int $start
  929. * @param int $stop Ps.以 -1 表示最后一个成员, -2 表示倒数第二个成员
  930. * @param boolean $withScore 返回值中是否带score字段 default(false)
  931. * @return array (index=>member) or assoc_array (member=>score) 用foreach(=>)取
  932. */
  933. public function zrevrange($key, $start, $stop, $withScore = false) {
  934. self::debug();
  935. if ($withScore) {
  936. $r = $this->redis->zrevrange($key, $start, $stop, 'WITHSCORES');
  937. return $r;
  938. } else {
  939. return $this->redis->zrevrange($key, $start, $stop);
  940. }
  941. }
  942. /**
  943. *
  944. * 有序列表 - 获取指定积分区间内的成员
  945. * @param string $key
  946. * @param int/float $min
  947. * @param int/float $max
  948. * @param boolean $withScore
  949. * @param bool $limit 是否限制返回值大小
  950. * @param int $offset 限制返回结果的起始位置
  951. * @param type $count 返回结果的数量
  952. * @return type
  953. */
  954. public function zrangebyscore($key, $min, $max, $withScore = false, $limit = false, $offset = 0, $count = 10) {
  955. self::debug();
  956. if ($limit) {
  957. if ($withScore) {
  958. return $this->redis->zrangebyscore($key, $min, $max, 'WITHSCORES', "LIMIT", $offset, $count);
  959. } else {
  960. return $this->redis->zrangebyscore($key, $min, $max, 'LIMIT', $offset, $count);
  961. }
  962. } else {
  963. if ($withScore) {
  964. return $this->redis->zrangebyscore($key, $min, $max, 'WITHSCORES');
  965. } else {
  966. return $this->redis->zrangebyscore($key, $min, $max);
  967. }
  968. }
  969. }
  970. /**
  971. *
  972. * 有序列表 - 获取按照倒序排序后指定积分区间内的成员
  973. * @param string $key
  974. * @param int/float $max
  975. * @param int/float $min
  976. * @param boolean $withScore
  977. * @param bool $limit 是否限制返回值大小
  978. * @param int $offset 限制返回结果的起始位置
  979. * @param type $count 返回结果的数量
  980. * @return type
  981. */
  982. public function zrevrangebyscore($key, $max, $min, $withScore = false, $limit = false, $offset = 0, $count = 10) {
  983. self::debug();
  984. if ($limit) {
  985. if ($withScore) {
  986. return $this->redis->zrevrangebyscore($key, $max, $min, 'WITHSCORES', "LIMIT", $offset, $count);
  987. } else {
  988. return $this->redis->zrevrangebyscore($key, $max, $min, 'LIMIT', $offset, $count);
  989. }
  990. } else {
  991. if ($withScore) {
  992. return $this->redis->zrevrangebyscore($key, $max, $min, 'WITHSCORES');
  993. } else {
  994. return $this->redis->zrevrangebyscore($key, $max, $min);
  995. }
  996. }
  997. }
  998. /**
  999. * 有序列表 - 根据元素反查排名
  1000. * @param string $key
  1001. * @param string $member
  1002. * @return int
  1003. */
  1004. public function zrank($key, $member) {
  1005. self::debug();
  1006. return $this->redis->zrank($key, $member);
  1007. }
  1008. /**
  1009. * 有序列表 - 查询某个成员的倒序排名
  1010. * @param string $key
  1011. * @param string $member
  1012. * @return int
  1013. */
  1014. public function zrevrank($key, $member) {
  1015. self::debug();
  1016. return $this->redis->zrevrank($key, $member);
  1017. }
  1018. /**
  1019. * 有序列表 - 根据元素反查积分
  1020. * @param string $key
  1021. * @param string $member
  1022. * @return int/float
  1023. */
  1024. public function zscore($key, $member) {
  1025. self::debug();
  1026. return $this->redis->zscore($key, $member);
  1027. }
  1028. /**
  1029. * 有序列表 - 移除元素
  1030. * @param string $key
  1031. * @param string $member
  1032. */
  1033. public function zrem($key, $member) {
  1034. self::debug();
  1035. $this->redis->zrem($key, $member);
  1036. }
  1037. /**
  1038. * 有序列表 - 移除指定区间的元素
  1039. * @param string $key
  1040. * @param int $start
  1041. * @param int $stop
  1042. */
  1043. public function zremrangebyrank($key, $start, $stop) {
  1044. self::debug();
  1045. $this->redis->zremrangebyrank($key, $start, $stop);
  1046. }
  1047. /**
  1048. * 有序列表 - 移除指定积分区间的元素.
  1049. * @param string $key
  1050. * @param int/float $min
  1051. * @param int/float $max
  1052. */
  1053. public function zremrangebyscore($key, $min, $max) {
  1054. self::debug();
  1055. $this->redis->zremrangebyscore($key, $min, $max);
  1056. }
  1057. /**
  1058. * 有序列表 - 复制有序类表到一个新的key
  1059. * @param string $key_source 源集合
  1060. * @param string $key_new 目标集合
  1061. */
  1062. public function zcopy($key_source, $key_new) {
  1063. self::debug();
  1064. $this->redis->zunionstore($key_new, 1, $key_source);
  1065. }
  1066. // </editor-fold>
  1067. //
  1068. // <editor-fold defaultstate="collapsed" desc=" 其他api ">
  1069. //
  1070. /**
  1071. * 重命名一个key(注意: 与move的区别, move是将数据迁移到其他db,rename相当于在当前db内move)
  1072. * @param type $key
  1073. * @param type $newkey
  1074. * @return boolean
  1075. */
  1076. public function rename($key, $newkey) {
  1077. self::debug();
  1078. return $this->redis->rename($key, $newkey) == "ok";
  1079. }
  1080. // == end of zSet ===
  1081. // * @method string zincrby($key, $increment, $member)
  1082. // * @method int zinterstore($destination, array $keys, array $options = null)
  1083. // * @method array zrevrangebyscore($key, $min, $max, array $options = null)
  1084. // * @method int zunionstore($destination, array $keys, array $options = null)
  1085. // * @method array zscan($key, $cursor, array $options = null)
  1086. // * @method array zrangebylex($key, $start, $stop, array $options = null)
  1087. // * @method int zremrangebylex($key, $min, $max)
  1088. // === end of zSet 操作 =====
  1089. // ======= hash 操作 ======
  1090. //
  1091. // // ======== set 操作 ======
  1092. // * @method array sdiff(array $keys)
  1093. // * @method int sdiffstore($destination, array $keys)
  1094. // * @method array sinter(array $keys)
  1095. // * @method int sinterstore($destination, array $keys)
  1096. //
  1097. // * @method int smove($source, $destination, $member)
  1098. // * @method string spop($key)
  1099. // * @method array sscan($key, $cursor, array $options = null)
  1100. // * @method array sunion(array $keys)
  1101. // * @method int sunionstore($destination, array $keys)
  1102. // ======= 订阅相关api =======s
  1103. // * @method int pfadd($key, array $elements)
  1104. // * @method mixed pfmerge($destinationKey, array $sourceKeys)
  1105. // * @method int pfcount(array $keys)
  1106. // * @method mixed pubsub($subcommand, $argument)
  1107. // * @method int publish($channel, $message)
  1108. // *
  1109. // ======= 事务相关api =======
  1110. // * @method mixed discard()
  1111. // * @method array exec()
  1112. // * @method mixed multi()
  1113. // * @method mixed unwatch()
  1114. // * @method mixed watch($key)
  1115. // ======= 执行lua脚本 =======
  1116. // * @method mixed eval($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
  1117. // * @method mixed evalsha($script, $numkeys, $keyOrArg1 = null, $keyOrArgN = null)
  1118. // * @method mixed script($subcommand, $argument = null)
  1119. // ======= 服务器操作api ======
  1120. // * @method mixed auth($password)
  1121. // * @method string echo($message)
  1122. // * @method mixed ping($message = null)
  1123. // * @method mixed select($database)
  1124. // * @method mixed bgrewriteaof()
  1125. // * @method mixed bgsave()
  1126. // </editor-fold>
  1127. }