workerId = $this->generateWorkerId(); } /** * 获取单例实例 */ public static function getInstance() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * 生成工作机器ID(基于服务器IP) */ protected function generateWorkerId() { // 方法1:从配置文件中读取 if (config('snowflake.worker_id')) { return config('snowflake.worker_id') & self::MAX_WORKER_ID; } // 方法2:基于服务器IP生成(推荐) $serverIp = $_SERVER['SERVER_ADDR'] ?? '127.0.0.1'; $ipParts = explode('.', $serverIp); // 使用IP后两段生成workerId if (count($ipParts) >= 4) { $workerId = ($ipParts[2] << 8) | $ipParts[3]; } else { // 如果是IPv6或特殊情况,使用随机数 $workerId = mt_rand(0, self::MAX_WORKER_ID); } return $workerId & self::MAX_WORKER_ID; } /** * 生成下一个ID */ public function nextId() { $timestamp = $this->getCurrentTimestamp(); // 时钟回拨处理 if ($timestamp < $this->lastTimestamp) { $diff = $this->lastTimestamp - $timestamp; throw new \Exception("时钟回拨了 {$diff} 毫秒"); } // 同一毫秒内生成多个ID if ($this->lastTimestamp == $timestamp) { $this->sequence = ($this->sequence + 1) & self::SEQUENCE_MASK; if ($this->sequence == 0) { // 序列号用尽,等待下一毫秒 $timestamp = $this->waitNextMillis($this->lastTimestamp); } } else { $this->sequence = 0; } $this->lastTimestamp = $timestamp; // 组合生成ID $id = (($timestamp - self::EPOCH) << self::TIMESTAMP_LEFT_SHIFT) | ($this->workerId << self::WORKER_ID_SHIFT) | $this->sequence; return (string)$id; } /** * 批量生成ID */ public function nextIds($count) { $ids = []; for ($i = 0; $i < $count; $i++) { $ids[] = $this->nextId(); } return $ids; } /** * 获取当前毫秒时间戳 */ protected function getCurrentTimestamp() { return (int)(microtime(true) * 1000); } /** * 等待到下一毫秒 */ protected function waitNextMillis($lastTimestamp) { $timestamp = $this->getCurrentTimestamp(); while ($timestamp <= $lastTimestamp) { usleep(100); // 休眠100微秒 $timestamp = $this->getCurrentTimestamp(); } return $timestamp; } /** * 解析雪花ID */ public static function parse($id) { $id = intval($id); return [ 'timestamp' => ($id >> self::TIMESTAMP_LEFT_SHIFT) + self::EPOCH, 'worker_id' => ($id >> self::WORKER_ID_SHIFT) & self::MAX_WORKER_ID, 'sequence' => $id & self::SEQUENCE_MASK, 'generated_at' => date('Y-m-d H:i:s.v', (($id >> self::TIMESTAMP_LEFT_SHIFT) + self::EPOCH) / 1000) ]; } }