add
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace app\utils;
|
||||
|
||||
/**
|
||||
* 雪花算法 - 分布式唯一ID生成器
|
||||
* Class Snowflake
|
||||
* @package app\utils
|
||||
*/
|
||||
class Snowflake
|
||||
{
|
||||
private const EPOCH = 1704067200000; // 2024-01-01 00:00:00 UTC
|
||||
private const WORKER_ID_BITS = 5;
|
||||
private const DATACENTER_ID_BITS = 5;
|
||||
private const SEQUENCE_BITS = 12;
|
||||
|
||||
private int $workerId;
|
||||
private int $datacenterId;
|
||||
private int $sequence = 0;
|
||||
private int $lastTimestamp = -1;
|
||||
|
||||
private static ?Snowflake $instance = null;
|
||||
|
||||
public function __construct(int $workerId = 1, int $datacenterId = 1)
|
||||
{
|
||||
$this->workerId = $workerId & 0x1F;
|
||||
$this->datacenterId = $datacenterId & 0x1F;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单例实例
|
||||
*/
|
||||
public static function getInstance(): Snowflake
|
||||
{
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self(1, 1);
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成下一个ID
|
||||
*/
|
||||
public function nextId(): int
|
||||
{
|
||||
$timestamp = $this->currentTimeMillis();
|
||||
|
||||
if ($timestamp === $this->lastTimestamp) {
|
||||
$this->sequence = ($this->sequence + 1) & 0xFFF;
|
||||
if ($this->sequence === 0) {
|
||||
$timestamp = $this->waitNextMillis($this->lastTimestamp);
|
||||
}
|
||||
} else {
|
||||
$this->sequence = 0;
|
||||
}
|
||||
|
||||
$this->lastTimestamp = $timestamp;
|
||||
|
||||
return (($timestamp - self::EPOCH) << 22)
|
||||
| ($this->datacenterId << 17)
|
||||
| ($this->workerId << 12)
|
||||
| $this->sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成字符串ID
|
||||
*/
|
||||
public function nextIdString(): string
|
||||
{
|
||||
return (string)$this->nextId();
|
||||
}
|
||||
|
||||
private function currentTimeMillis(): int
|
||||
{
|
||||
return (int)(microtime(true) * 1000);
|
||||
}
|
||||
|
||||
private function waitNextMillis(int $lastTimestamp): int
|
||||
{
|
||||
$timestamp = $this->currentTimeMillis();
|
||||
while ($timestamp <= $lastTimestamp) {
|
||||
$timestamp = $this->currentTimeMillis();
|
||||
}
|
||||
return $timestamp;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user