<?php
namespace app\extend;
/**
* 雪花算法分布式ID生成器
*/
class SnowFlake
{
const EPOCH = 1479533469598; // 自定义纪元起点 (2016-11-20)
const MAX_MACHINE_ID = 1023; // 10位机器ID最大值
const MAX_SEQUENCE = 4095; // 12位序列号最大值
private static int $machineId = 0; // 机器ID (0-1023)
private static int $lastTimestamp = 0; // 上次生成时间戳
private static int $sequence = 0; // 序列号
/**
* 设置机器ID
* @param int $mId 0-1023
*/
public static function setMachineId(int $mId): void
{
if ($mId < 0 || $mId > self::MAX_MACHINE_ID) {
throw new \InvalidArgumentException("机器ID范围0-1023");
}
self::$machineId = $mId;
}
/**
* 生成分布式ID (64位长整型字符串)
* @return string
*/
public static function generateId(): string
{
$timestamp = self::getCurrentTimestamp();
if ($timestamp < self::$lastTimestamp) {
throw new \RuntimeException("时钟回退,拒绝生成ID");
}
if ($timestamp === self::$lastTimestamp) {
self::$sequence = (self::$sequence + 1) & self::MAX_SEQUENCE;
if (self::$sequence === 0) {
$timestamp = self::waitNextMillis(self::$lastTimestamp);
}
} else {
self::$sequence = 0;
}
self::$lastTimestamp = $timestamp;
// 组合64位二进制 (时间戳42位 + 机器ID10位 + 序列号12位)
$binary = sprintf(
"%042b%010b%012b",
$timestamp - self::EPOCH,
self::$machineId,
self::$sequence
);
return self::binaryToDecimal($binary);
}
/**
* 从ID解析生成时间戳 (毫秒)
* @param string $id
* @return int
*/
public static function parseTime(string $id): int
{
$binary = self::decimalToBinary($id);
$timeBits = substr($binary, 0, 42);
return (int)bindec($timeBits) + self::EPOCH;
}
//--------------------- 私有方法 ---------------------
private static function getCurrentTimestamp(): int
{
return (int)round(microtime(true) * 1000);
}
private static function waitNextMillis(int $lastTimestamp): int
{
$timestamp = self::getCurrentTimestamp();
while ($timestamp <= $lastTimestamp) {
usleep(1000);
$timestamp = self::getCurrentTimestamp();
}
return $timestamp;
}
private static function binaryToDecimal(string $binary): string
{
$decimal = '0';
$length = strlen($binary);
for ($i = 0; $i < $length; $i++) {
$decimal = bcmul($decimal, '2');
$decimal = bcadd($decimal, $binary[$i]);
}
return $decimal;
}
private static function decimalToBinary(string $decimal): string
{
$binary = '';
$num = $decimal;
while ($num !== '0') {
$binary = bcmod($num, '2') . $binary;
$num = bcdiv($num, '2', 0);
}
return str_pad($binary, 64, '0', STR_PAD_LEFT);
}
}
雪花ID | 订单编号 生成类
于 2025-12-26 11:07:15 首次发布
482

被折叠的 条评论
为什么被折叠?



