test_lgq/niucloud/core/util/Snowflake.php
2024-01-24 17:36:08 +08:00

91 lines
2.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace core\util;
use Exception;
class Snowflake
{
// 起始的时间戳
const START_EPOCH = 1609459200000; // 2021-01-01 00:00:00
// 各部分所占位数
const SEQUENCE_BITS = 12;
const MACHINE_ID_BITS = 0;
const DATA_CENTER_ID_BITS = 0;
// 最大值
const MAX_SEQUENCE = 4095;
const MAX_MACHINE_ID = 31;
const MAX_DATA_CENTER_ID = 31;
private $data_center_id;
private $machine_id;
private $last_timestamp;
private $sequence;
public function __construct($data_center_id, $machine_id)
{
// if ($data_center_id > self::MAX_DATA_CENTER_ID || $data_center_id < 0) {
// throw new Exception('Data center ID can not be greater than ' . self::MAX_DATA_CENTER_ID . ' or less than 0');
// }
//
// if ($machine_id > self::MAX_MACHINE_ID || $machine_id < 0) {
// throw new Exception('Machine ID can not be greater than ' . self::MAX_MACHINE_ID . ' or less than 0');
// }
// $this->data_center_id = $data_center_id;
// $this->machine_id = $machine_id;
$this->last_timestamp = 0;
$this->sequence = 0;
}
/**
* @throws Exception
*/
public function generateId()
{
$timestamp = $this->getTimestamp();
// 当前时间小于上一次生成时间,发生时钟回拨
if ($timestamp < $this->last_timestamp) {
throw new Exception('Clock moved backwards.');
}
// 当前时间与上一次生成时间相同
if ($timestamp == $this->last_timestamp) {
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
// 当前毫秒的序列已经达到最大值,等待下一毫秒
if ($this->sequence == 0) {
$timestamp = $this->nextMillis($this->last_timestamp);
}
} else {
// 新的一毫秒序列从0开始
$this->sequence = 0;
}
$this->last_timestamp = $timestamp;
return (($timestamp - self::START_EPOCH) << (self::SEQUENCE_BITS))
// | ($this->data_center_id << (self::SEQUENCE_BITS + self::MACHINE_ID_BITS))
// | ($this->machine_id << self::SEQUENCE_BITS)
| $this->sequence;
}
private function getTimestamp()
{
return floor(microtime(true) * 1000);
}
private function nextMillis($last_timestamp)
{
$timestamp = $this->getTimestamp();
while ($timestamp <= $last_timestamp) {
$timestamp = $this->getTimestamp();
}
return $timestamp;
}
}