PHP_伟仔博客

PHP 结合redis 实现排行榜

2021-10-20 09:29:41  浏览:452  作者:管理员
<?php namespace app\social\extend; use think\Exception; class RedisLeaderboard {    /**     *     * @var object redis client     */    private $redis;    /**     *     * @var string 放置排行榜的key     */    private $leaderboard;    private $_config;    //>>.分数后面加解决分数一样排名先后问题    private $key=9999999999999;    /**     * 初始化     * @param Array $config redis连接设定     */    public function __construct($config=array(),$db=0,$leaderboard=''){        $this->_config = $config;        $this->redis = $this->connect($db);        if ($leaderboard) {            //这里不会检查当前的key值是否存在,是为了方便重新访问对应的排行榜            $this->leaderboard = $leaderboard;        } else {            $this->leaderboard = 'leaderboard:' . mt_rand(1, 100000); //            while (!empty($this->redis->exists($this->leaderboard))) { //                $this->leaderboard = 'leaderboard:' . mt_rand(1, 100000); //            }        }    }    /**     * 创建redis连接     * @return Link     */    private function connect($db){        try{            $redis = new \Redis();            $redis->connect($this->_config['host']);            $redis->auth($this->_config['auth']);            empty($db)?'':$redis->select($db);        }catch(\RedisException $e){            throw new Exception($e->getMessage());        }        return $redis;    }    /**     * 获取当前的排行榜的key名     * @return string     */    public function getLeaderboard()    {        return $this->leaderboard;    }    /**     * 将对应的值填入到排行榜中     * @param  $node 对应的需要填入的值(比如商品的id)     * @param number $count 对应的分数,默认值为1     * @param bool $time 默认毫秒级     * @return Long 1 if the element is added. 0 otherwise.     */    public function addLeaderboard($node, $count = 1,$time=true)    {        $count=$count.''.($this->key-$this->getMillisecond($time));//>>.解决分数一样的问题        return $this->redis->zAdd($this->leaderboard, $count, $node);    }    /**     * 默认毫秒     * 毫秒级     * @param $time     * @return float|int     */    public function getMillisecond($time=true) {        if($time===false) return time();        list($s1, $s2) = explode(' ', microtime());        return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);    }    /**     * 给出对应的排行榜     * @param int $number 需要给出排行榜数目     * @param bool $asc 排序顺序 true为按照高分为第0     * @param bool $withscores 是否需要分数     * @param callback $callback 用于处理排行榜的回调函数     * @return [] 对应排行榜     */    public function getLeadboard($number, $asc = true, $withscores = false,$callback = null)    {        if ($asc) {            $nowLeadboard =  $this->redis->zRevRange($this->leaderboard, 0, $number -1, $withscores);//按照高分数顺序排行;        } else {            $nowLeadboard =  $this->redis->zRange($this->leaderboard, 0, $number -1, $withscores);//按照低分数顺序排行;        }        if ($callback) {            //使用回调处理            return $callback($nowLeadboard);        } else {            return $nowLeadboard;        }    }    //>>.获取前后排名    /**     * 给定ID获取排名     * @param $node     * @param int $c     * @return array|bool     */    public function getRevRange($node,$c=5){        $ranking=$this->getNodeRank($node);        if($ranking===false) return false;        $start=$ranking-$c;        //>>.解决负数的问题        if($start<0) $start=0;        $end=$ranking+$c;        $ranking=$this->redis->zRevRange($this->leaderboard,$start,$end,true);        //>>.获取用户的名次        $data=[];        foreach ($ranking as $key=>$v){            $ranking_=$this->getNodeRank($key);            $v=$this->processingScores($v);            $data[$key]=['id'=>$key,'score'=>$v,'ranking'=>($ranking_+1),];        }        return $data;    }    /**     * 获取给定节点的排名     * @param string $node 对应的节点的key名     * @param string $asc 是否按照分数大小正序排名, true的情况下分数越大,排名越高     * @return 节点排名,根据$asc排序,true的话,第一高分为0,false的话第一低分为0     */    public function getNodeRank($node, $asc = true)    {        if ($asc) {            //zRevRank 分数最高的排行为0,所以需要加1位            return $this->redis->zRevRank($this->leaderboard, $node);        } else {            return $this->redis->zRank($this->leaderboard, $node);        }    }    /**     * 获取分数,并且已经处理过的     * @param $node     * @return bool|float     */    public function getScore($node){        $score=$this->redis->zScore($this->leaderboard, $node);        //>>.解决科学计算        $score=number_format($score,0,'','');        return   $this->processingScores($score);    }    /**     * 处理分数     * @param $score     * @return false|string     */    private function processingScores($score){        //>>.解决科学计算        $score=number_format($score,0,'','');        return   substr($score, 0, -13);    } }


上一篇:已经是第一篇

下一篇:已经是最后一篇

评论区

共 0 条评论
  • 这篇文章还没有收到评论,赶紧来抢沙发吧~

【随机内容】

返回顶部