<?php
namespace framework\components\uniqueid;
use framework\base\Component;
class UniqueId extends Component
{
const twepoch = 1474992000000
const workerIdBits = 10;
const sequenceBits = 12;
protected $workId = 0;
protected $lastTimestamp = -1;
protected $sequence = 0;
protected function init()
{
if(SYSTEM_WORK_ID< 0){
$this->triggerThrowable(new \Exception("workerId can't be less than 0", 500));
}
$this->workId = SYSTEM_WORK_ID;
}
public function nextId()
{
$timestamp = $this->timeGen();
$lastTimestamp = $this->lastTimestamp;
if ($timestamp < $lastTimestamp) {
$time = $lastTimestamp - $timestamp;
$this->triggerThrowable(new \Exception("Clock moved backwards. Refusing to generate id for $time milliseconds", 500));
}
if ($lastTimestamp == $timestamp) {
$sequenceMask = -1 ^ (-1 << self::sequenceBits);
$this->sequence = ($this->sequence + 1) & $sequenceMask;
if ($this->sequence == 0) {
$timestamp = $this->tilNextMillis($lastTimestamp);
}
} else {
$this->sequence = 0;
}
$this->lastTimestamp = $timestamp;
$timestampLeftShift = self::sequenceBits + self::workerIdBits;
$workerIdShift = self::sequenceBits;
$nextId = (($timestamp - self::twepoch) << $timestampLeftShift) | ($this->workId << $workerIdShift) | $this->sequence;
return $nextId;
}
protected function timeGen()
{
$timestramp = (float)\sprintf("%.0f", \microtime(true) * 1000);
return $timestramp;
}
protected function tilNextMillis($lastTimestamp)
{
$timestamp = $this->timeGen();
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->timeGen();
}
return $timestamp;
}
}