雪花算法
<?php
class Snowflake
{
private $epoch;
private $datacenterId;
private $workerId;
private $sequence;
private $datacenterIdBits = 5;
private $workerIdBits = 5;
private $sequenceBits = 12;
private $timestampBits = 41;
private $maxDatacenterId;
private $maxWorkerId;
private $maxSequence;
private $workerIdShift;
private $datacenterIdShift;
private $timestampLeftShift;
private $lastTimestamp = -1;
public function __construct(int $datacenterId, int $workerId, int $epoch = 1695030884971)
{
$this->maxDatacenterId = -1 ^ (-1 << $this->datacenterIdBits);
$this->maxWorkerId = -1 ^ (-1 << $this->workerIdBits);
$this->maxSequence = -1 ^ (-1 << $this->sequenceBits);
if ($datacenterId > $this->maxDatacenterId || $datacenterId < 0) {
throw new \Exception("Datacenter ID超出范围");
}
if ($workerId > $this->maxWorkerId || $workerId < 0) {
throw new \Exception("Worker ID超出范围");
}
$this->workerIdShift = $this->sequenceBits;
$this->datacenterIdShift = $this->sequenceBits + $this->workerIdBits;
$this->timestampLeftShift = $this->timestampBits;
$this->datacenterId = $datacenterId;
$this->workerId = $workerId;
$this->epoch = $epoch;
}
public function generateId(): int
{
$timestamp = $this->getTimestamp();
if ($timestamp < $this->lastTimestamp) {
throw new \Exception("系统时钟发生回退");
}
if ($timestamp == $this->lastTimestamp) {
$this->sequence = ($this->sequence + 1) & $this->maxSequence;
if ($this->sequence === 0) {
$timestamp = $this->waitNextMillis($this->lastTimestamp);
}
} else {
$this->sequence = 0;
}
$this->lastTimestamp = $timestamp;
$id = (($timestamp - $this->epoch) << $this->timestampLeftShift) |
($this->datacenterId << $this->datacenterIdShift) |
($this->workerId << $this->workerIdShift) |
$this->sequence;
return $id;
}
private function getTimestamp(): int
{
return (int) floor(microtime(true) * 1000);
}
private function waitNextMillis($lastTimestamp): int
{
$timestamp = $this->getTimestamp();
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->getTimestamp();
}
return $timestamp;
}
}
10进制转62进制
public function decimalToBase62($decimal) {
$base62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
$base62_length = strlen($base62)
$result = ''
while ($decimal > 0) {
$remainder = $decimal % $base62_length
$result .= $base62[$remainder]
$decimal = intdiv($decimal, $base62_length)
}
return strrev($result)
}
62进制转10进制
public function base62ToDecimal($number) {
$base62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
$base62_length = strlen($base62)
$number = strrev($number)
$dec = 0
for ($i = 0
$digit = strpos($base62, $number[$i])
$dec += $digit * pow($base62_length, $i)
}
return $dec
}