From f9de7a3a063125b9df9dc8c1f895400ffb11057a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=8D=8E=E6=B8=85?= <18691022700@163.com> Date: Fri, 26 Dec 2025 11:47:14 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=AA=E8=8A=B1=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/common/library/Snowflake.php | 122 +++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 application/common/library/Snowflake.php diff --git a/application/common/library/Snowflake.php b/application/common/library/Snowflake.php new file mode 100644 index 00000000..951b3ef5 --- /dev/null +++ b/application/common/library/Snowflake.php @@ -0,0 +1,122 @@ + self::MAX_MACHINE_ID) { + throw new \InvalidArgumentException("机器ID必须在0-" . self::MAX_MACHINE_ID . "之间"); + } + + $this->machineId = $machineId; + } + + /** + * 生成ID + * @return string + */ + public function generateId() + { + $timestamp = $this->getTimestamp(); + + if ($timestamp < $this->lastTimestamp) { + throw new \Exception("时钟回拨异常"); + } + + 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; + } + + $this->lastTimestamp = $timestamp; + + return (($timestamp - self::EPOCH) << self::TIMESTAMP_SHIFT) | + ($this->machineId << self::MACHINE_SHIFT) | + $this->sequence; + } + + /** + * 获取当前毫秒时间戳 + * @return int + */ + private function getTimestamp() + { + return (int)(microtime(true) * 1000); + } + + /** + * 等待下一毫秒 + * @param int $lastTimestamp + * @return int + */ + private function waitNextMillis($lastTimestamp) + { + $timestamp = $this->getTimestamp(); + while ($timestamp <= $lastTimestamp) { + usleep(100); // 休眠100微秒 + $timestamp = $this->getTimestamp(); + } + return $timestamp; + } + + /** + * 解析ID + * @param string $id + * @return array + */ + public static function parseId($id) + { + $timestamp = ($id >> self::TIMESTAMP_SHIFT) + self::EPOCH; + $machineId = ($id >> self::MACHINE_SHIFT) & self::MAX_MACHINE_ID; + $sequence = $id & self::MAX_SEQUENCE; + + return [ + 'timestamp' => $timestamp, + 'machine_id' => $machineId, + 'sequence' => $sequence, + 'generate_time' => date('Y-m-d H:i:s', $timestamp / 1000) + ]; + } +} \ No newline at end of file