不同AI生成的PHP版雪花算法
OpenAI
<?php
/**
* Snowflake 雪花算法生成器
* 生成的 64 位 ID 结构:
* 1 位 保留位(始终为0,防止负数)
* 41 位 时间戳(毫秒级,当前时间减去自定义纪元)
* 5 位 数据中心ID
* 5 位 机器ID
* 12 位 序列号(同一毫秒内生成多个 ID)
*/
class Snowflake
{
// 自定义纪元(起始时间戳),可根据实际情况调整
private $twepoch = 1288834974657;
// 各部分占用的位数
private $workerIdBits = 5; // 机器ID位数
private $datacenterIdBits = 5; // 数据中心ID位数
private $sequenceBits = 12; // 序列号位数
// 各部分的最大数值(通过位运算计算)
private $maxWorkerId;
private $maxDatacenterId;
private $sequenceMask;
// 各部分左移位数
private $workerIdShift;
private $datacenterIdShift;
private $timestampLeftShift;
// 工作机器ID和数据中心ID(取值范围 0 ~ 最大值)
private $workerId;
private $datacenterId;
// 序列号,记录同一毫秒内生成的ID序号
private $sequence = 0;
// 上一次生成ID的时间戳,初始化为 -1
private $lastTimestamp = -1;
/**
* 构造函数
*
* @param int $workerId 机器ID(0 ~ 31)
* @param int $datacenterId 数据中心ID(0 ~ 31)
*/
public function __construct($workerId, $datacenterId)
{
// 计算各部分最大值:如 -1 << 5 得到 0b11111 (31)
$this->maxWorkerId = -1 ^ (-1 << $this->workerIdBits);
$this->maxDatacenterId = -1 ^ (-1 << $this->datacenterIdBits);
// 序列号最大值(4095:12位全1)
$this->sequenceMask = -1 ^ (-1 << $this->sequenceBits);
// 检查传入的机器ID和数据中心ID是否合法
if ($workerId > $this->maxWorkerId || $workerId < 0) {
throw new Exception("机器ID必须在 0 到 " . $this->maxWorkerId . " 之间");
}
if ($datacenterId > $this->maxDatacenterId || $datacenterId < 0) {
throw new Exception("数据中心ID必须在 0 到 " . $this->maxDatacenterId . " 之间");
}
$this->workerId = $workerId;
$this->datacenterId = $datacenterId;
// 计算各部分需要左移的位数
// 序列号占用 12 位,因此机器ID需要左移 12 位
$this->workerIdShift = $this->sequenceBits;
// 数据中心ID需要左移 12 + 5 = 17 位
$this->datacenterIdShift = $this->sequenceBits + $this->workerIdBits;
// 时间戳需要左移 12 + 5 + 5 = 22 位
$this->timestampLeftShift = $this->sequenceBits + $this->workerIdBits + $this->datacenterIdBits;
}
/**
* 生成下一个唯一ID
*
* @return int 64位的唯一ID
*/
public function nextId()
{
// 获取当前毫秒级时间戳
$timestamp = $this->timeGen();
// 如果当前时间小于上一次生成ID的时间戳,则说明系统时钟回拨,无法生成ID
if ($timestamp < $this->lastTimestamp) {
throw new Exception("时钟回拨异常,拒绝生成ID. 差值: " . ($this->lastTimestamp - $timestamp) . " 毫秒");
}
// 如果当前时间与上次生成ID时间相同,表示同一毫秒内生成多个ID
if ($timestamp == $this->lastTimestamp) {
// 序列号自增,并通过位运算确保在 12 位内(最大值为 4095)
$this->sequence = ($this->sequence + 1) & $this->sequenceMask;
// 如果序列号达到最大值,则等待下一毫秒
if ($this->sequence == 0) {
$timestamp = $this->tilNextMillis($this->lastTimestamp);
}
} else {
// 不同毫秒内,序列号重置为 0
$this->sequence = 0;
}
// 更新上一次生成ID的时间戳
$this->lastTimestamp = $timestamp;
/**
* 拼接各部分生成最终ID:
* 1. (当前时间戳 - 自定义纪元) 左移 TIMESTAMP_LEFT_SHIFT 位
* 2. 数据中心ID左移 DATACENTER_ID_SHIFT 位
* 3. 机器ID左移 WORKER_ID_SHIFT 位
* 4. 序列号(低12位)
* 最终通过按位或(|)运算组合成一个 64 位的整数
*/
$id = (($timestamp - $this->twepoch) << $this->timestampLeftShift)
| ($this->datacenterId << $this->datacenterIdShift)
| ($this->workerId << $this->workerIdShift)
| $this->sequence;
return $id;
}
/**
* 等待直到下一毫秒
*
* @param int $lastTimestamp 上次生成ID的时间戳
* @return int 下一毫秒的时间戳
*/
private function tilNextMillis($lastTimestamp)
{
$timestamp = $this->timeGen();
// 循环等待直到时间戳发生变化(进入下一毫秒)
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->timeGen();
}
return $timestamp;
}
/**
* 获取当前时间戳(毫秒级)
*
* @return int 当前毫秒级时间戳
*/
private function timeGen()
{
// microtime(true) 返回秒为单位的小数,将其乘以 1000 转换为毫秒
return (int) (microtime(true) * 1000);
}
}
// ------------------------- 测试示例 ------------------------- //
// 创建一个 Snowflake 实例,指定机器ID和数据中心ID
try {
$snowflake = new Snowflake(1, 1);
// 生成 10 个唯一ID,并输出
for ($i = 0; $i < 10; $i++) {
echo "生成的ID " . ($i + 1) . " : " . $snowflake->nextId() . "\n";
}
} catch (Exception $e) {
echo "异常:" . $e->getMessage();
}
?>
DeepSeek
<?php
/**
* 雪花算法分布式ID生成器
* 结构:0 | 时间戳(41位) | 数据中心ID(5位) | 机器ID(5位) | 序列号(12位)
*/
class Snowflake
{
// 起始时间戳(2024-01-01 00:00:00 UTC)
const EPOCH = 1704067200000;
// 位数分配
const SEQUENCE_BITS = 12; // 序列号位数
const MACHINE_BITS = 5; // 机器标识位数
const DATACENTER_BITS = 5; // 数据中心位数
// 最大值计算(位运算优化)
const MAX_SEQUENCE = -1 ^ (-1 << self::SEQUENCE_BITS);
const MAX_MACHINE = -1 ^ (-1 << self::MACHINE_BITS);
const MAX_DATACENTER = -1 ^ (-1 << self::DATACENTER_BITS);
// 移位偏移量计算
const TIMESTAMP_SHIFT = self::SEQUENCE_BITS + self::MACHINE_BITS + self::DATACENTER_BITS;
const DATACENTER_SHIFT = self::SEQUENCE_BITS + self::MACHINE_BITS;
const MACHINE_SHIFT = self::SEQUENCE_BITS;
private $machineId; // 机器标识ID
private $datacenterId; // 数据中心ID
private $sequence = 0; // 序列号
private $lastTimestamp = -1; // 上次生成时间戳
/**
* 构造函数
* @param int $machineId 机器ID (0~31)
* @param int $datacenterId 数据中心ID (0~31)
*/
public function __construct($machineId, $datacenterId)
{
// 参数校验
if ($machineId > self::MAX_MACHINE || $machineId < 0) {
throw new InvalidArgumentException("机器ID值超出范围(0~".self::MAX_MACHINE.")");
}
if ($datacenterId > self::MAX_DATACENTER || $datacenterId < 0) {
throw new InvalidArgumentException("数据中心ID值超出范围(0~".self::MAX_DATACENTER.")");
}
$this->machineId = $machineId;
$this->datacenterId = $datacenterId;
}
/**
* 生成下一个分布式ID
* @return int 64位整型ID(PHP中实际返回字符串类型以保证精度)
*/
public function generateId()
{
$timestamp = $this->getCurrentTimestamp();
// 时钟回拨检查
if ($timestamp < $this->lastTimestamp) {
$diff = $this->lastTimestamp - $timestamp;
throw new RuntimeException("系统时钟回拨 {$diff} 毫秒");
}
// 同一毫秒内生成
if ($this->lastTimestamp == $timestamp) {
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
// 序列号耗尽,等待下一毫秒
if ($this->sequence == 0) {
$timestamp = $this->waitNextMillis($this->lastTimestamp);
}
} else {
// 新时间戳重置序列号
$this->sequence = 0;
}
$this->lastTimestamp = $timestamp;
// 组合各部分数据
$id = (($timestamp) << self::TIMESTAMP_SHIFT)
| ($this->datacenterId << self::DATACENTER_SHIFT)
| ($this->machineId << self::MACHINE_SHIFT)
| $this->sequence;
// 返回字符串类型以避免32位系统精度丢失
return (string)$id;
}
/**
* 阻塞到下一毫秒
* @param int $lastTimestamp 上次生成时间戳
* @return int 当前时间戳
*/
private function waitNextMillis($lastTimestamp)
{
$timestamp = $this->getCurrentTimestamp();
while ($timestamp <= $lastTimestamp) {
usleep(1000); // 休眠1毫秒
$timestamp = $this->getCurrentTimestamp();
}
return $timestamp;
}
/**
* 获取当前时间戳(毫秒)
* @return int 毫秒时间戳
*/
private function getCurrentTimestamp()
{
return round(microtime(true) * 1000) - self::EPOCH;
}
}
/* 使用示例 */
try {
$snowflake = new Snowflake(1, 1); // 机器ID=1,数据中心ID=1
// 生成10个ID
for ($i = 0; $i < 10; $i++) {
echo $snowflake->generateId() . PHP_EOL;
}
} catch (Exception $e) {
echo $e->getMessage();
}
Kimi
<?php
/**
* 雪花算法生成唯一ID
* 基于Twitter的Snowflake算法,生成一个64位的唯一ID
*/
class Snowflake
{
// 以下是各个部分所占的位数
const SIGN_BIT = 1; // 符号位,始终为0
const TIMESTAMP_BIT = 41; // 时间戳位数
const DATA_CENTER_ID_BIT = 5; // 数据中心ID位数
const WORKER_ID_BIT = 5; // 机器节点ID位数
const SEQUENCE_BIT = 12; // 序列号位数
// 最大值
const MAX_DATA_CENTER_ID = -1 ^ (-1 << self::DATA_CENTER_ID_BIT); // 31
const MAX_WORKER_ID = -1 ^ (-1 << self::WORKER_ID_BIT); // 31
const MAX_SEQUENCE = -1 ^ (-1 << self::SEQUENCE_BIT); // 4095
// 每一部分的偏移量
const DATA_CENTER_ID_SHIFT = self::SEQUENCE_BIT;
const WORKER_ID_SHIFT = self::SEQUENCE_BIT + self::DATA_CENTER_ID_BIT;
const TIMESTAMP_SHIFT = self::SEQUENCE_BIT + self::DATA_CENTER_ID_BIT + self::WORKER_ID_BIT;
// 开始时间戳(2023-01-01 00:00:00的毫秒数)
const EPOCH = 1672502400000;
// 数据中心ID和机器节点ID
private $dataCenterId;
private $workerId;
// 序列号
private $sequence = 0;
// 上一次的时间戳
private $lastTimestamp = -1;
/**
* 构造函数
* @param int $dataCenterId 数据中心ID
* @param int $workerId 机器节点ID
*/
public function __construct($dataCenterId = 0, $workerId = 0)
{
if ($dataCenterId > self::MAX_DATA_CENTER_ID || $dataCenterId < 0) {
throw new \InvalidArgumentException("dataCenterId不能大于" . self::MAX_DATA_CENTER_ID . "或小于0");
}
if ($workerId > self::MAX_WORKER_ID || $workerId < 0) {
throw new \InvalidArgumentException("workerId不能大于" . self::MAX_WORKER_ID . "或小于0");
}
$this->dataCenterId = $dataCenterId;
$this->workerId = $workerId;
}
/**
* 生成唯一ID
* @return int 唯一ID
*/
public function generateId()
{
$currentTimestamp = $this->getCurrentTimestamp();
if ($currentTimestamp < $this->lastTimestamp) {
throw new \RuntimeException("时间戳回退,拒绝生成ID");
}
if ($currentTimestamp == $this->lastTimestamp) {
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
if ($this->sequence == 0) {
$currentTimestamp = $this->tilNextMillis($this->lastTimestamp);
}
} else {
$this->sequence = 0;
}
$this->lastTimestamp = $currentTimestamp;
// ID拼接
$id = (($currentTimestamp - self::EPOCH) << self::TIMESTAMP_SHIFT)
| ($this->dataCenterId << self::DATA_CENTER_ID_SHIFT)
| ($this->workerId << self::WORKER_ID_SHIFT)
| $this->sequence;
return $id;
}
/**
* 等待下一毫秒
* @param int $lastTimestamp 上一次的时间戳
* @return int 当前时间戳
*/
private function tilNextMillis($lastTimestamp)
{
$timestamp = $this->getCurrentTimestamp();
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->getCurrentTimestamp();
}
return $timestamp;
}
/**
* 获取当前时间戳(毫秒)
* @return int 当前时间戳
*/
private function getCurrentTimestamp()
{
return round(microtime(true) * 1000);
}
}
// 使用示例
$snowflake = new Snowflake(1, 2); // 数据中心ID为1,机器节点ID为2
$id = $snowflake->generateId();
echo $id;
智谱清言
<?php
/**
* Snowflake ID生成类,基于Twitter的Snowflake算法
*/
class Snowflake {
// 雪花算法常量定义
const EPOCH = 1288834974657; // 起始时间戳,单位毫秒
const DATA_CENTER_ID_BITS = 5; // 数据中心ID所占的位数
const MACHINE_ID_BITS = 5; // 机器ID所占的位数
const SEQUENCE_BITS = 12; // 序列号所占的位数
const MAX_DATA_CENTER_ID = (1 << self::DATA_CENTER_ID_BITS) - 1; // 最大的数据中心ID
const MAX_MACHINE_ID = (1 << self::MACHINE_ID_BITS) - 1; // 最大的机器ID
const MAX_SEQUENCE = (1 << self::SEQUENCE_BITS) - 1; // 最大的序列号
const MACHINE_ID_SHIFT = self::SEQUENCE_BITS; // 机器ID的偏移量
const DATA_CENTER_ID_SHIFT = self::MACHINE_ID_SHIFT + self::MACHINE_ID_BITS; // 数据中心ID的偏移量
const TIMESTAMP_SHIFT = self::DATA_CENTER_ID_SHIFT + self::DATA_CENTER_ID_BITS; // 时间戳的偏移量
private $dataCenterId; // 数据中心ID
private $machineId; // 机器ID
private $sequence = 0; // 序列号
private $lastTimestamp = -1; // 上一次生成ID的时间戳
/**
* 构造函数
* @param int $dataCenterId 数据中心ID,范围0到31
* @param int $machineId 机器ID,范围0到31
*/
public function __construct($dataCenterId,$machineId) {
if ($dataCenterId < 0 ||$dataCenterId > self::MAX_DATA_CENTER_ID) {
throw new InvalidArgumentException("数据中心ID必须在0和" . self::MAX_DATA_CENTER_ID . "之间");
}
if ($machineId < 0 ||$machineId > self::MAX_MACHINE_ID) {
throw new InvalidArgumentException("机器ID必须在0和" . self::MAX_MACHINE_ID . "之间");
}
$this->dataCenterId =$dataCenterId;
$this->machineId =$machineId;
}
/**
* 生成下一个ID
* @return string 生成的ID字符串
*/
public function nextId() {
$timestamp =$this->timeGen();
// 如果当前时间戳小于上一次的时间戳,说明时钟回拨
if ($timestamp <$this->lastTimestamp) {
throw new RuntimeException("时钟回拨,拒绝生成ID");
}
// 如果当前时间戳与上一次的时间戳相同,同一毫秒内生成多个ID
if ($timestamp ==$this->lastTimestamp) {
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
// 如果序列号达到最大值,等待下一毫秒
if ($this->sequence == 0) {
$timestamp =$this->tilNextMillis($this->lastTimestamp);
}
} else {
// 如果进入新的毫秒,序列号重置为0
$this->sequence = 0;
}
// 更新上一次的时间戳
$this->lastTimestamp =$timestamp;
// 生成ID
$id = (($timestamp - self::EPOCH) << self::TIMESTAMP_SHIFT) |
($this->dataCenterId << self::DATA_CENTER_ID_SHIFT) |
($this->machineId << self::MACHINE_ID_SHIFT) |
$this->sequence;
return strval($id);
}
/**
* 获取当前时间戳,单位毫秒
* @return int
*/
private function timeGen() {
return floor(microtime(true) * 1000);
}
/**
* 等待下一毫秒,直到时间戳增加
* @param int $lastTimestamp 上一次的时间戳
* @return int 当前时间戳
*/
private function tilNextMillis($lastTimestamp) {
$timestamp =$this->timeGen();
while ($timestamp <=$lastTimestamp) {
$timestamp =$this->timeGen();
}
return $timestamp;
}
}
// 使用示例
try {
// 创建Snowflake实例,数据中心ID为1,机器ID为1
$snowflake = new Snowflake(1, 1);
// 生成并输出10个唯一ID
for ($i = 0;$i < 10; $i++) {
$id =$snowflake->nextId();
echo $id . "\n";
}
// 创建另一个Snowflake实例,数据中心ID为1,机器ID为2
$snowflake2 = new Snowflake(1, 2);
// 生成并输出10个唯一ID
for ($i = 0;$i < 10; $i++) {
$id =$snowflake2->nextId();
echo $id . "\n";
}
// 创建另一个Snowflake实例,数据中心ID为2,机器ID为1
$snowflake3 = new Snowflake(2, 1);
// 生成并输出10个唯一ID
for ($i = 0;$i < 10; $i++) {
$id =$snowflake3->nextId();
echo $id . "\n";
}
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
Claude
<?php
/**
* 雪花算法(Snowflake)PHP实现
*
* 雪花算法是由Twitter开发的分布式ID生成算法,能够在分布式系统中产生唯一的ID
* 该算法生成的ID结构为64位长整型,由以下部分组成:
* 1. 1位符号位,固定为0(表示正数)
* 2. 41位时间戳(毫秒级),可使用约69年
* 3. 10位工作机器ID,包括5位数据中心ID和5位机器ID,最多支持32个数据中心和每个中心下32台机器
* 4. 12位序列号,1毫秒内最多生成4096个ID
*/
class Snowflake {
/**
* 开始时间戳(2020-01-01)
* 这是算法的基准时间,用于计算相对时间戳
*/
const START_TIMESTAMP = 1577808000000; // 2020-01-01 00:00:00 GMT
/**
* 各部分占用的位数
*/
const SEQUENCE_BITS = 12; // 序列号占用的位数
const MACHINE_ID_BITS = 5; // 机器ID占用的位数
const DATACENTER_ID_BITS = 5; // 数据中心ID占用的位数
/**
* 各部分的最大值
*/
const MAX_SEQUENCE = -1 ^ (-1 << self::SEQUENCE_BITS); // 序列号最大值 4095
const MAX_MACHINE_ID = -1 ^ (-1 << self::MACHINE_ID_BITS); // 机器ID最大值 31
const MAX_DATACENTER_ID = -1 ^ (-1 << self::DATACENTER_ID_BITS);// 数据中心ID最大值 31
/**
* 各部分向左的位移
*/
const MACHINE_ID_SHIFT = self::SEQUENCE_BITS; // 机器ID向左移12位
const DATACENTER_ID_SHIFT = self::SEQUENCE_BITS + self::MACHINE_ID_BITS; // 数据中心ID向左移17位
const TIMESTAMP_SHIFT = self::SEQUENCE_BITS + self::MACHINE_ID_BITS + self::DATACENTER_ID_BITS; // 时间戳向左移22位
/**
* 数据中心ID
* @var int
*/
private $datacenterId;
/**
* 机器ID
* @var int
*/
private $machineId;
/**
* 毫秒内序列号
* @var int
*/
private $sequence = 0;
/**
* 上次生成ID的时间戳
* @var int
*/
private $lastTimestamp = -1;
/**
* 构造函数
*
* @param int $datacenterId 数据中心ID (0~31)
* @param int $machineId 机器ID (0~31)
* @throws Exception 当数据中心ID或机器ID超出范围时抛出异常
*/
public function __construct($datacenterId, $machineId) {
// 参数校验
if ($datacenterId > self::MAX_DATACENTER_ID || $datacenterId < 0) {
throw new Exception("数据中心ID不能大于".self::MAX_DATACENTER_ID."或小于0");
}
if ($machineId > self::MAX_MACHINE_ID || $machineId < 0) {
throw new Exception("机器ID不能大于".self::MAX_MACHINE_ID."或小于0");
}
$this->datacenterId = $datacenterId;
$this->machineId = $machineId;
}
/**
* 获取当前时间戳(毫秒)
*
* @return int 当前时间戳(毫秒)
*/
private function getCurrentTimestamp() {
// 获取当前时间戳,单位为毫秒
return floor(microtime(true) * 1000);
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
*
* @param int $lastTimestamp 上次生成ID的时间戳
* @return int 新的时间戳
*/
private function waitNextMillis($lastTimestamp) {
$timestamp = $this->getCurrentTimestamp();
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->getCurrentTimestamp();
}
return $timestamp;
}
/**
* 生成ID
*
* @return string 返回生成的ID(字符串形式,因为PHP整数范围有限)
* @throws Exception 当时钟回拨时抛出异常
*/
public function nextId() {
// 获取当前时间戳
$timestamp = $this->getCurrentTimestamp();
// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过,抛出异常
if ($timestamp < $this->lastTimestamp) {
throw new Exception("时钟向后移动,拒绝生成ID,时间差: " . ($this->lastTimestamp - $timestamp) . " 毫秒");
}
// 如果是同一时间生成的,则进行毫秒内序列号递增
if ($timestamp == $this->lastTimestamp) {
// 序列号递增
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
// 同一毫秒内序列号已经达到最大值,阻塞到下一个毫秒
if ($this->sequence == 0) {
$timestamp = $this->waitNextMillis($this->lastTimestamp);
}
} else {
// 时间戳改变,毫秒内序列号重置为0
$this->sequence = 0;
}
// 记录上次生成ID的时间戳
$this->lastTimestamp = $timestamp;
// 计算相对时间戳(与起始时间的差值)
$relativeTimestamp = $timestamp - self::START_TIMESTAMP;
// 组装ID并返回
// 使用字符串拼接,避免PHP整数溢出问题
$id = (($relativeTimestamp << self::TIMESTAMP_SHIFT) |
($this->datacenterId << self::DATACENTER_ID_SHIFT) |
($this->machineId << self::MACHINE_ID_SHIFT) |
$this->sequence);
// 转换为字符串,避免潜在的整数溢出问题
return (string)$id;
}
}
// 使用示例
try {
// 创建一个雪花算法实例,参数为数据中心ID和机器ID
$snowflake = new Snowflake(1, 1);
// 生成ID
$id = $snowflake->nextId();
echo "生成的ID: " . $id . PHP_EOL;
// 批量生成多个ID
echo "批量生成5个ID:" . PHP_EOL;
for ($i = 0; $i < 5; $i++) {
echo $snowflake->nextId() . PHP_EOL;
}
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . PHP_EOL;
}
?>
豆包
<?php
class Snowflake {
// 起始时间戳,一般设置为项目开始的时间,单位:毫秒
const EPOCH = 1609459200000;
// 数据中心 ID 所占的位数
const DATA_CENTER_ID_BITS = 5;
// 机器 ID 所占的位数
const WORKER_ID_BITS = 5;
// 序列号所占的位数
const SEQUENCE_BITS = 12;
// 数据中心 ID 最大值
const MAX_DATA_CENTER_ID = -1 ^ (-1 << self::DATA_CENTER_ID_BITS);
// 机器 ID 最大值
const MAX_WORKER_ID = -1 ^ (-1 << self::WORKER_ID_BITS);
// 序列号最大值
const MAX_SEQUENCE = -1 ^ (-1 << self::SEQUENCE_BITS);
// 机器 ID 向左移位数
const WORKER_ID_SHIFT = self::SEQUENCE_BITS;
// 数据中心 ID 向左移位数
const DATA_CENTER_ID_SHIFT = self::SEQUENCE_BITS + self::WORKER_ID_BITS;
// 时间戳向左移位数
const TIMESTAMP_LEFT_SHIFT = self::SEQUENCE_BITS + self::WORKER_ID_BITS + self::DATA_CENTER_ID_BITS;
// 数据中心 ID
private $dataCenterId;
// 机器 ID
private $workerId;
// 序列号
private $sequence = 0;
// 上一次生成 ID 的时间戳
private $lastTimestamp = -1;
/**
* 构造函数,初始化数据中心 ID 和机器 ID
*
* @param int $dataCenterId 数据中心 ID
* @param int $workerId 机器 ID
* @throws Exception 如果数据中心 ID 或机器 ID 超出范围,抛出异常
*/
public function __construct($dataCenterId, $workerId) {
// 检查数据中心 ID 是否在合法范围内
if ($dataCenterId > self::MAX_DATA_CENTER_ID || $dataCenterId < 0) {
throw new Exception("Data center ID must be between 0 and " . self::MAX_DATA_CENTER_ID);
}
// 检查机器 ID 是否在合法范围内
if ($workerId > self::MAX_WORKER_ID || $workerId < 0) {
throw new Exception("Worker ID must be between 0 and " . self::MAX_WORKER_ID);
}
$this->dataCenterId = $dataCenterId;
$this->workerId = $workerId;
}
/**
* 生成下一个唯一的 ID
*
* @return int 生成的唯一 ID
* @throws Exception 如果系统时钟回拨,抛出异常
*/
public function nextId() {
// 获取当前时间戳,单位:毫秒
$timestamp = $this->getCurrentTimestamp();
// 处理时钟回拨问题
if ($timestamp < $this->lastTimestamp) {
throw new Exception("Clock moved backwards. Refusing to generate id for " . ($this->lastTimestamp - $timestamp) . " milliseconds");
}
if ($timestamp == $this->lastTimestamp) {
// 如果在同一毫秒内,序列号递增
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
if ($this->sequence == 0) {
// 序列号达到最大值,等待下一毫秒
$timestamp = $this->waitNextMillis($this->lastTimestamp);
}
} else {
// 时间戳改变,重置序列号
$this->sequence = 0;
}
// 更新上一次生成 ID 的时间戳
$this->lastTimestamp = $timestamp;
// 生成最终的 ID
return (($timestamp - self::EPOCH) << self::TIMESTAMP_LEFT_SHIFT) |
($this->dataCenterId << self::DATA_CENTER_ID_SHIFT) |
($this->workerId << self::WORKER_ID_SHIFT) |
$this->sequence;
}
/**
* 获取当前时间戳,单位:毫秒
*
* @return int 当前时间戳
*/
private function getCurrentTimestamp() {
return floor(microtime(true) * 1000);
}
/**
* 等待下一毫秒
*
* @param int $lastTimestamp 上一次生成 ID 的时间戳
* @return int 下一毫秒的时间戳
*/
private function waitNextMillis($lastTimestamp) {
$timestamp = $this->getCurrentTimestamp();
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->getCurrentTimestamp();
}
return $timestamp;
}
}
// 使用示例
try {
// 创建 Snowflake 实例,指定数据中心 ID 和机器 ID
$snowflake = new Snowflake(1, 1);
// 生成唯一 ID
$id = $snowflake->nextId();
echo "Generated ID: " . $id;
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
腾讯元宝
<?php
class Snowflake
{
// 数据中心ID所占位数(5位,支持32个数据中心)
const DATA_CENTER_ID_BITS = 5;
// 机器ID所占位数(5位,支持32台机器)
const MACHINE_ID_BITS = 5;
// 序列号所占位数(12位,每毫秒支持4096个ID)
const SEQUENCE_BITS = 12;
// 最大数据中心ID(2^5 - 1)
const MAX_DATA_CENTER_ID = -1 ^ (-1 << self::DATA_CENTER_ID_BITS);
// 最大机器ID(2^5 - 1)
const MAX_MACHINE_ID = -1 ^ (-1 << self::MACHINE_ID_BITS);
// 时间戳左移位数(41+5+5=51位)
const TIMESTAMP_LEFT_SHIFT = self::SEQUENCE_BITS + self::MACHINE_ID_BITS + self::DATA_CENTER_ID_BITS;
// 机器ID左移位数(41+5=46位)
const SEQUENCE_LEFT_SHIFT = self::MACHINE_ID_BITS + self::DATA_CENTER_ID_BITS;
// 起始时间戳(2021-01-01 00:00:00,可自定义)
private $epoch = 1609430400000;
// 实例属性
private int $datacenterId; // 数据中心ID
private int $machineId; // 机器ID
private int $sequence = 0; // 序列号
private int $lastTimestamp = -1; // 上次生成ID的时间戳
/**
* 构造函数,初始化ID生成器
* @param int $datacenterId 数据中心ID(0-31)
* @param int $machineId 机器ID(0-31)
* @throws Exception 如果ID超出范围
*/
public function __construct(int $datacenterId, int $machineId)
{
// 验证数据中心ID范围
if ($datacenterId < 0 || $datacenterId > self::MAX_DATA_CENTER_ID) {
throw new Exception("数据中心ID超出范围");
}
// 验证机器ID范围
if ($machineId < 0 || $machineId > self::MAX_MACHINE_ID) {
throw new Exception("机器ID超出范围");
}
$this->datacenterId = $datacenterId;
$this->machineId = $machineId;
}
/**
* 生成唯一ID
* @return int 64位唯一ID
* @throws Exception 如果时钟发生回拨
*/
public function nextId(): int
{
$timestamp = $this->currentTimeMillis();
// 检测时钟回拨
if ($timestamp < $this->lastTimestamp) {
throw new Exception("错误:系统时钟发生回拨");
}
// 同一毫秒内处理序列号递增
if ($this->lastTimestamp === $timestamp) {
$this->sequence = ($this->sequence + 1) & ((1 << self::SEQUENCE_BITS) - 1);
// 序列号溢出,等待下一毫秒
if ($this->sequence === 0) {
$timestamp = $this->waitNextMillis($timestamp);
}
} else {
// 新的一毫秒,重置序列号
$this->sequence = 0;
}
// 更新上次时间戳
$this->lastTimestamp = $timestamp;
// 组合ID:(时间戳 << 22) | (数据中心ID << 17) | (机器ID << 12) | 序列号
return (($timestamp - $this->epoch) << self::TIMESTAMP_LEFT_SHIFT) |
($this->datacenterId << self::SEQUENCE_LEFT_SHIFT) |
($this->machineId << self::SEQUENCE_BITS) |
$this->sequence;
}
/**
* 等待下一毫秒
* @param int $lastTimestamp 上次时间戳
* @return int 下一毫秒时间戳
*/
private function waitNextMillis(int $lastTimestamp): int
{
$timestamp = $this->currentTimeMillis();
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->currentTimeMillis();
}
return $timestamp;
}
/**
* 获取当前时间戳(毫秒级)
* @return int
*/
private function currentTimeMillis(): int
{
return (int)(microtime(true) * 1000);
}
}
// 使用示例
$datacenterId = 1; // 数据中心ID(0-31)
$machineId = 1; // 机器ID(0-31)
$snowflake = new Snowflake($datacenterId, $machineId);
for ($i = 0; $i < 10; $i++) {
$userId = $snowflake->nextId();
echo "生成的用户ID: {$userId}<br/>";
}
Vercel
<?php
/**
* 雪花算法(Snowflake)PHP实现
*
* 雪花算法是由Twitter开发的分布式唯一ID生成算法,结构如下:
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
*
* 第1位:符号位,始终为0
* 第2-42位:41位时间戳(毫秒级),可以使用69年
* 第43-43位:1位数据中心ID
* 第44-48位:5位机器ID
* 第49-53位:5位数据中心内机器ID
* 第54-64位:12位序列号,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒产生4096个ID序号
*/
class Snowflake {
/**
* 开始时间戳(2020-01-01)
* 这是一个自定义的起始时间,用于计算相对时间戳
*/
const START_TIMESTAMP = 1577808000000; // 2020-01-01 00:00:00 GMT
/**
* 各部分占用的位数
*/
const SEQUENCE_BITS = 12; // 序列号占用的位数
const MACHINE_ID_BITS = 5; // 机器ID占用的位数
const DATACENTER_ID_BITS = 5; // 数据中心ID占用的位数
/**
* 各部分的最大值
*/
const MAX_SEQUENCE = -1 ^ (-1 << self::SEQUENCE_BITS); // 序列号最大值 4095
const MAX_MACHINE_ID = -1 ^ (-1 << self::MACHINE_ID_BITS); // 机器ID最大值 31
const MAX_DATACENTER_ID = -1 ^ (-1 << self::DATACENTER_ID_BITS); // 数据中心ID最大值 31
/**
* 各部分向左的位移
*/
const MACHINE_ID_SHIFT = self::SEQUENCE_BITS; // 机器ID向左移12位
const DATACENTER_ID_SHIFT = self::SEQUENCE_BITS + self::MACHINE_ID_BITS; // 数据中心ID向左移17位
const TIMESTAMP_SHIFT = self::SEQUENCE_BITS + self::MACHINE_ID_BITS + self::DATACENTER_ID_BITS; // 时间戳向左移22位
/**
* @var int 数据中心ID
*/
private $datacenterId;
/**
* @var int 机器ID
*/
private $machineId;
/**
* @var int 毫秒内序列号
*/
private $sequence = 0;
/**
* @var int 上次生成ID的时间戳
*/
private $lastTimestamp = -1;
/**
* 构造函数
*
* @param int $datacenterId 数据中心ID (0~31)
* @param int $machineId 机器ID (0~31)
* @throws Exception 当数据中心ID或机器ID超出范围时抛出异常
*/
public function __construct($datacenterId = 0, $machineId = 0) {
// 检查数据中心ID和机器ID是否在有效范围内
if ($datacenterId > self::MAX_DATACENTER_ID || $datacenterId < 0) {
throw new Exception("数据中心ID超出范围: 应为0~" . self::MAX_DATACENTER_ID);
}
if ($machineId > self::MAX_MACHINE_ID || $machineId < 0) {
throw new Exception("机器ID超出范围: 应为0~" . self::MAX_MACHINE_ID);
}
$this->datacenterId = $datacenterId;
$this->machineId = $machineId;
}
/**
* 获取下一个ID
*
* @return string 生成的ID(返回字符串是因为PHP的整数范围可能不足以存储64位ID)
* @throws Exception 当时钟回拨时抛出异常
*/
public function nextId() {
// 获取当前时间戳(毫秒)
$timestamp = $this->getCurrentTimestamp();
// 检查时钟回拨
if ($timestamp < $this->lastTimestamp) {
throw new Exception("时钟回拨,拒绝生成ID,上次时间: " .
$this->lastTimestamp . ", 当前时间: " . $timestamp);
}
// 如果是同一毫秒内,则增加序列号
if ($timestamp == $this->lastTimestamp) {
// 序列号递增
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
// 如果序列号溢出,则等待下一毫秒
if ($this->sequence == 0) {
$timestamp = $this->waitNextMillis($this->lastTimestamp);
}
} else {
// 不同毫秒内,序列号重置为0
$this->sequence = 0;
}
// 更新上次生成ID的时间戳
$this->lastTimestamp = $timestamp;
// 计算相对时间戳(相对于开始时间)
$timestampDiff = $timestamp - self::START_TIMESTAMP;
// 组合各部分生成ID
// 注意:PHP的整数范围可能不足以存储64位ID,所以使用字符串或GMP扩展处理大整数
$id = (($timestampDiff << self::TIMESTAMP_SHIFT) |
($this->datacenterId << self::DATACENTER_ID_SHIFT) |
($this->machineId << self::MACHINE_ID_SHIFT) |
$this->sequence);
return (string)$id;
}
/**
* 获取当前时间戳(毫秒)
*
* @return int 当前时间戳(毫秒)
*/
private function getCurrentTimestamp() {
// 获取微秒级时间戳并转换为毫秒
return (int)floor(microtime(true) * 1000);
}
/**
* 等待下一毫秒
*
* @param int $lastTimestamp 上次生成ID的时间戳
* @return int 新的时间戳(毫秒)
*/
private function waitNextMillis($lastTimestamp) {
$timestamp = $this->getCurrentTimestamp();
// 循环等待,直到获得新的时间戳
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->getCurrentTimestamp();
}
return $timestamp;
}
}
// 使用示例
try {
// 创建雪花算法实例,参数为数据中心ID和机器ID
$snowflake = new Snowflake(1, 1);
// 生成10个ID
echo "生成的ID示例:\n";
for ($i = 0; $i < 10; $i++) {
echo $snowflake->nextId() . "\n";
}
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
文心一言
<?php
class Snowflake {
// 定义雪花ID的各部分位数
private const TIMESTAMP_BITS = 41; // 时间戳位数
private const NODE_ID_BITS = 10; // 节点ID位数
private const SEQUENCE_BITS = 12; // 序列号位数
// 定义起始时间戳(这里以2020-01-01为例)
private const EPOCH = 1577836800000;
// 定义最大取值范围
private const MAX_NODE_ID = (1 << self::NODE_ID_BITS) - 1;
private const MAX_SEQUENCE = (1 << self::SEQUENCE_BITS) - 1;
// 定义偏移量
private const TIMESTAMP_SHIFT = self::NODE_ID_BITS + self::SEQUENCE_BITS;
private const NODE_ID_SHIFT = self::SEQUENCE_BITS;
private $nodeId; // 节点ID
private $lastTimestamp = -1; // 上次生成ID的时间戳
private $sequence = 0; // 序列号
/**
* 构造函数,用于初始化节点ID
*
* @param int $nodeId 节点ID
* @throws InvalidArgumentException 如果节点ID超出范围
*/
public function __construct($nodeId) {
if ($nodeId < 0 || $nodeId > self::MAX_NODE_ID) {
throw new InvalidArgumentException("Invalid node ID, must be between 0 and " . self::MAX_NODE_ID);
}
$this->nodeId = $nodeId;
}
/**
* 生成下一个唯一的ID
*
* @return int 生成的唯一ID
* @throws RuntimeException 如果系统时钟回拨
*/
public function generateId() {
$currentTimestamp = $this->timestamp();
// 检查时钟回拨
if ($currentTimestamp < $this->lastTimestamp) {
throw new RuntimeException("Clock moved backwards");
}
// 如果当前时间戳与上次相同,则递增序列号
if ($currentTimestamp == $this->lastTimestamp) {
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
// 如果序列号溢出,则等待下一毫秒
if ($this->sequence == 0) {
$currentTimestamp = $this->untilNextMillis($this->lastTimestamp);
}
} else {
// 如果时间戳不同,则重置序列号
$this->sequence = 0;
}
// 更新上次生成ID的时间戳
$this->lastTimestamp = $currentTimestamp;
// 组合时间戳、节点ID和序列号生成唯一的ID
return (($currentTimestamp - self::EPOCH) << self::TIMESTAMP_SHIFT) |
($this->nodeId << self::NODE_ID_SHIFT) |
$this->sequence;
}
/**
* 获取当前时间戳(毫秒)
*
* @return int 当前时间戳
*/
private function timestamp() {
return round(microtime(true) * 1000);
}
/**
* 等待下一毫秒
*
* @param int $lastTimestamp 上次生成ID的时间戳
* @return int 下一毫秒的时间戳
*/
private function untilNextMillis($lastTimestamp) {
$currentTimestamp = $this->timestamp();
while ($currentTimestamp <= $lastTimestamp) {
$currentTimestamp = $this->timestamp();
}
return $currentTimestamp;
}
}
// 示例使用
$nodeId = 1; // 设置节点ID
$snowflake = new Snowflake($nodeId);
// 生成10个唯一ID
for ($i = 0; $i < 10; $i++) {
$id = $snowflake->generateId();
echo "Generated ID: $id\n";
}
讯飞星火
讯飞星火在生成代码的过程中居然出现了BUG, 代码在生成过程中, 开头生成的代码莫名消失, 最后生成的代码如下
self::MAX_DATA_CENTER_ID || $dataCenterId < 0) {
throw new Exception("Data Center ID can't be greater than " . self::MAX_DATA_CENTER_ID . " or less than 0");
}
if ($machineId > self::MAX_MACHINE_ID || $machineId < 0) {
throw new Exception("Machine ID can't be greater than " . self::MAX_MACHINE_ID . " or less than 0");
}
$this->dataCenterId = $dataCenterId;
$this->machineId = $machineId;
}
public function nextId() {
$timestamp = $this->timeGen();
if ($timestamp < $this->lastTimestamp) {
throw new Exception("Clock moved backwards. Refusing to generate id for " . ($this->lastTimestamp - $timestamp) . " milliseconds");
}
if ($this->lastTimestamp == $timestamp) {
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
if ($this->sequence == 0) {
$timestamp = $this->tilNextMillis($this->lastTimestamp);
}
} else {
$this->sequence = 0;
}
$this->lastTimestamp = $timestamp;
return (($timestamp - self::EPOCH) << self::TIMESTAMP_SHIFT) |
($this->dataCenterId << self::DATA_CENTER_ID_SHIFT) |
($this->machineId << self::MACHINE_ID_SHIFT) |
$this->sequence;
}
protected function tilNextMillis($lastTimestamp) {
$timestamp = $this->timeGen();
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->timeGen();
}
return $timestamp;
}
protected function timeGen() {
return round(microtime(true) * 1000); // 获取当前时间的毫秒级时间戳
}
}
// 使用示例
try {
$snowflake = new Snowflake(1, 1); // 数据中心ID和机器ID都设置为1
echo $snowflake->nextId(); // 生成一个唯一的ID
} catch (Exception $e) {
echo 'Error: ' . $e->getMessage();
}
?>