分布式架构-雪花算法-php类库

2 篇文章 0 订阅
2 篇文章 0 订阅
<?php
/**
 * ID 生成策略
 * 毫秒级时间41位+机器ID, 10位+毫秒内序列12位。高位始终为0,表示正数。
 * 0           41     51     64
 * +-----------+------+------+
 * |time       |pc    |inc   |
 * +-----------+------+------+
 *  前41bits是以微秒为单位的timestamp。
 *  接着10bits是事先配置好的机器ID。
 *  最后12bits是累加计数器。
 *  macheine id(10bits)标明最多只能有1024台机器同时产生ID,sequence number(12bits)也标明1台机器1ms中最多产生4096个ID,
 *
 */
class IdWork
{
    private static $workerId;
    private static $maxWorkerId = 1023; //最大的机器节点, 2^10 - 1

    private static $sequence = 0;
    private static $sequenceMask = 4095; //最大的序列节点, 2^12 - 1

    private static $workerIdShift = 12; //机器ID左移位数,63 - 51
    private static $timestampLeftShift = 22; //毫秒时间戳左移位数,63 - 41

    private static $twepoch = 1288834974657;
    private static $lastTimestamp = -1;

    /**
     * @var self
     */
    private static $self = null;

    /**
     * @return self
     */
    public static function getInstance()
    {
        if (self::$self == null) {
            self::$self = new self();
        }
        return self::$self;
    }

    public function setWorkId($workId)
    {
        if ($workId > self::$maxWorkerId || $workId < 0) {
            throw new \Exception("worker Id can't be greater than ".self::$maxWorkerId." or less than 0");
        }
        self::$workerId = $workId;
        return self::$self;
    }

    private function timeGen()
    {
        //获得当前时间戳
        $time = explode(' ', microtime());
        $time2 = substr($time[0], 2, 3);
        return $time[1] . $time2;
    }

    private function tilNextMillis($lastTimestamp)
    {
        $timestamp = $this->timeGen();
        while ($timestamp <= $lastTimestamp) {
            $timestamp = $this->timeGen();
        }
        return $timestamp;
    }

    public function nextId()
    {
        $timestamp = $this->timeGen();

        //如果存在并发调用,则自增sequence
        if (self::$lastTimestamp == $timestamp) {
            self::$sequence = (self::$sequence + 1) & self::$sequenceMask;

            //如果sequence自增到4095,也就是4096 & 4095 = 0,重新取时间戳
            if (self::$sequence == 0) {
                $timestamp = $this->tilNextMillis(self::$lastTimestamp);
            }
        } else {
            self::$sequence = 0;
        }

        if ($timestamp < self::$lastTimestamp) {
            throw new \Exception("Clock moved backwards.  Refusing to generate id for " . (self::$lastTimestamp - $timestamp) . " milliseconds");
        }

        self::$lastTimestamp = $timestamp;

        if (PHP_INT_SIZE === 4) {
            return 0;
        }

        $nextId = ((sprintf('%.0f', $timestamp) - sprintf(
            '%.0f',
            self::$twepoch
        )) << self::$timestampLeftShift) | (self::$workerId << self::$workerIdShift) | self::$sequence;

        return $nextId;
    }
}

使用方法

//第一步,定义一个随机数
$rand = rand(0,1023);
$order_no = IdWork::getInstance()->setWorkId($wordId)->nextId();
return '您好!您的订单号为'.$order_no;

!输出结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值