<?php

class Snowflake
{
    const EPOCH = 1609459200000; // 自定义纪元时间:2021-01-01 00:00:00 UTC(毫秒)
    const TIMESTAMP_BITS = 41;
    const DATA_CENTER_BITS = 5;
    const MACHINE_BITS = 5;
    const SEQUENCE_BITS = 12;

    const MAX_DATA_CENTER_ID = (1 << self::DATA_CENTER_BITS) - 1; // 31
    const MAX_MACHINE_ID = (1 << self::MACHINE_BITS) - 1;         // 31
    const MAX_SEQUENCE = (1 << self::SEQUENCE_BITS) - 1;          // 4095

    private $dataCenterId;
    private $machineId;
    private $sequence = 0;
    private $lastTimestamp = 0;

    public function __construct($dataCenterId = 0, $machineId = 0)
    {
        if ($dataCenterId > self::MAX_DATA_CENTER_ID || $dataCenterId < 0) {
            throw new InvalidArgumentException("Data center ID can't be greater than " . self::MAX_DATA_CENTER_ID);
        }
        if ($machineId > self::MAX_MACHINE_ID || $machineId < 0) {
            throw new InvalidArgumentException("Machine ID can't be greater than " . self::MAX_MACHINE_ID);
        }

        $this->dataCenterId = $dataCenterId;
        $this->machineId = $machineId;
    }

    /**
     * 生成唯一ID
     */
    public function nextId(): int
    {
        $timestamp = $this->timeGen();

        // 防止时钟回拨
        if ($timestamp < $this->lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID.");
        }

        // 同一毫秒内:序列号递增
        if ($timestamp === $this->lastTimestamp) {
            $this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
            if ($this->sequence === 0) {
                // 等待下一毫秒
                $timestamp = $this->tilNextMillis($this->lastTimestamp);
            }
        } else {
            $this->sequence = 0; // 新毫秒,序列重置
        }

        $this->lastTimestamp = $timestamp;

        $timestamp -= self::EPOCH;

        // 组合64位ID
        return ($timestamp << (self::DATA_CENTER_BITS + self::MACHINE_BITS + self::SEQUENCE_BITS))
               | ($this->dataCenterId << (self::MACHINE_BITS + self::SEQUENCE_BITS))
               | ($this->machineId << self::SEQUENCE_BITS)
               | $this->sequence;
    }

    /**
     * 阻塞到下一个毫秒
     */
    private function tilNextMillis($lastTimestamp)
    {
        $timestamp = $this->timeGen();
        while ($timestamp <= $lastTimestamp) {
            $timestamp = $this->timeGen();
        }
        return $timestamp;
    }

    /**
     * 获取当前时间戳(毫秒)
     */
    private function timeGen(): int
    {
        return (int)(microtime(true) * 1000);
    }

    /**
     * 解析 Snowflake ID(调试用)
     */
    public function parseId(int $id): array
    {
        $sequence = $id & self::MAX_SEQUENCE;
        $machineId = ($id >> self::SEQUENCE_BITS) & self::MAX_MACHINE_ID;
        $dataCenterId = ($id >> (self::SEQUENCE_BITS + self::MACHINE_BITS)) & self::MAX_DATA_CENTER_ID;
        $timestamp = ($id >> (self::SEQUENCE_BITS + self::MACHINE_BITS + self::DATA_CENTER_BITS)) + self::EPOCH;

        return [
            'timestamp' => $timestamp,
            'datetime' => date('Y-m-d H:i:s.v', $timestamp / 1000),
            'data_center_id' => $dataCenterId,
            'machine_id' => $machineId,
            'sequence' => $sequence,
        ];
    }
}
// 创建 Snowflake 实例(数据中心ID=1,机器ID=1)
$snowflake = new Snowflake(1, 1);

// 生成多个 ID
for ($i = 0; $i < 5; $i++) {
    $id = $snowflake->nextId();
    echo $id . "\n";
    usleep(1000); // 延迟1毫秒,避免序列号冲突
}

?>

更多推荐