Snowflake.php 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. <?php
  2. namespace core\util;
  3. use Exception;
  4. class Snowflake
  5. {
  6. // 起始的时间戳
  7. const START_EPOCH = 1609459200000; // 2021-01-01 00:00:00
  8. // 各部分所占位数
  9. const SEQUENCE_BITS = 12;
  10. const MACHINE_ID_BITS = 0;
  11. const DATA_CENTER_ID_BITS = 0;
  12. // 最大值
  13. const MAX_SEQUENCE = 4095;
  14. const MAX_MACHINE_ID = 31;
  15. const MAX_DATA_CENTER_ID = 31;
  16. private $data_center_id;
  17. private $machine_id;
  18. private $last_timestamp;
  19. private $sequence;
  20. public function __construct($data_center_id, $machine_id)
  21. {
  22. // if ($data_center_id > self::MAX_DATA_CENTER_ID || $data_center_id < 0) {
  23. // throw new Exception('Data center ID can not be greater than ' . self::MAX_DATA_CENTER_ID . ' or less than 0');
  24. // }
  25. //
  26. // if ($machine_id > self::MAX_MACHINE_ID || $machine_id < 0) {
  27. // throw new Exception('Machine ID can not be greater than ' . self::MAX_MACHINE_ID . ' or less than 0');
  28. // }
  29. // $this->data_center_id = $data_center_id;
  30. // $this->machine_id = $machine_id;
  31. $this->last_timestamp = 0;
  32. $this->sequence = 0;
  33. }
  34. /**
  35. * @throws Exception
  36. */
  37. public function generateId()
  38. {
  39. $timestamp = $this->getTimestamp();
  40. // 当前时间小于上一次生成时间,发生时钟回拨
  41. if ($timestamp < $this->last_timestamp) {
  42. throw new Exception('Clock moved backwards.');
  43. }
  44. // 当前时间与上一次生成时间相同
  45. if ($timestamp == $this->last_timestamp) {
  46. $this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
  47. // 当前毫秒的序列已经达到最大值,等待下一毫秒
  48. if ($this->sequence == 0) {
  49. $timestamp = $this->nextMillis($this->last_timestamp);
  50. }
  51. } else {
  52. // 新的一毫秒,序列从0开始
  53. $this->sequence = 0;
  54. }
  55. $this->last_timestamp = $timestamp;
  56. return (($timestamp - self::START_EPOCH) << (self::SEQUENCE_BITS))
  57. // | ($this->data_center_id << (self::SEQUENCE_BITS + self::MACHINE_ID_BITS))
  58. // | ($this->machine_id << self::SEQUENCE_BITS)
  59. | $this->sequence;
  60. }
  61. private function getTimestamp()
  62. {
  63. return floor(microtime(true) * 1000);
  64. }
  65. private function nextMillis($last_timestamp)
  66. {
  67. $timestamp = $this->getTimestamp();
  68. while ($timestamp <= $last_timestamp) {
  69. $timestamp = $this->getTimestamp();
  70. }
  71. return $timestamp;
  72. }
  73. }