Socket/app/utils/Snowflake.php
2026-01-28 23:48:20 +08:00

87 lines
2.0 KiB
PHP

<?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;
}
}