本文目录导读:

在 PHP 中生成“趋势唯一”的值,通常有几种不同的理解,我猜测您可能有以下几种需求,我分别给出解决方案:
基于时间戳的唯一ID(带趋势性)
如果您想要按时间递增的唯一ID(类似雪花算法),这样数据库索引效率高:
<?php
/**
* 生成趋势递增的唯一ID(类Twitter雪花算法)
* 64位:1位符号 + 41位时间戳 + 10位机器ID + 12位序列号
*/
class SnowflakeId {
private $workerId;
private $sequence = 0;
private $lastTimestamp = -1;
// 开始时间戳(2020-01-01)
private $twepoch = 1577808000000;
public function __construct($workerId = 0) {
$this->workerId = $workerId & 0x3FF; // 10位
}
public function nextId() {
$timestamp = $this->currentTimeMillis();
// 时钟回拨处理
if ($timestamp < $this->lastTimestamp) {
throw new Exception("Clock moved backwards");
}
if ($timestamp == $this->lastTimestamp) {
$this->sequence = ($this->sequence + 1) & 0xFFF; // 12位序列号
if ($this->sequence == 0) {
// 等待下一毫秒
$timestamp = $this->waitNextMillis($this->lastTimestamp);
}
} else {
$this->sequence = 0;
}
$this->lastTimestamp = $timestamp;
// 组合:时间戳 + 机器ID + 序列号
return (($timestamp - $this->twepoch) << 22) |
($this->workerId << 12) |
$this->sequence;
}
private function currentTimeMillis() {
return (int)(microtime(true) * 1000);
}
private function waitNextMillis($lastTimestamp) {
$timestamp = $this->currentTimeMillis();
while ($timestamp <= $lastTimestamp) {
$timestamp = $this->currentTimeMillis();
}
return $timestamp;
}
}
// 使用示例
$snowflake = new SnowflakeId(1);
$uniqueId = $snowflake->nextId();
echo $uniqueId . "\n";
echo "时间戳: " . (($uniqueId >> 22) + 1577808000000) . "\n";
带时间戳的字符串唯一ID(人类可读)
如果您想要格式化的、肉眼可见趋势的唯一字符串:
<?php
/**
* 生成带时间戳的唯一ID字符串
* 格式:20240101-154530-123456
*/
function generateTimedUniqueId($prefix = '') {
// 当前时间
$date = date('Ymd-His');
// 毫秒
$milliseconds = (int)(microtime(true) * 1000) % 1000;
// 随机数(防止同一毫秒冲突)
$random = bin2hex(random_bytes(4));
return $prefix . $date . '-' . str_pad($milliseconds, 3, '0', STR_PAD_LEFT) . '-' . $random;
}
// 使用示例
echo generateTimedUniqueId('USER_');
// 输出:USER_20240101-154530-123-3f8a2b1c
数据库友好的趋势ID(自增+时间戳)
如果您在数据库中使用,可以结合自增ID和时间戳:
<?php
/**
* 生成用于数据库的趋势性唯一ID
* 结构:时间戳(8位16进制) + 随机数(8位16进制) + 哈希
*/
function generateDatabaseTrendId($data = '') {
// 时间戳(秒 + 微秒)
$timestamp = dechex(time());
$microtime = dechex((int)(microtime() * 1000000) % 16);
// 基于数据的哈希
$hash = substr(hash('md5', $timestamp . $data . uniqid()), 0, 8);
// 随机数
$random = bin2hex(random_bytes(4));
return $timestamp . $microtime . $hash . $random;
}
轻量级通用方案(推荐简单场景)
如果您不需要太复杂,PHP自带函数组合:
<?php
/**
* 简易趋势唯一ID(推荐)
*/
function simpleTrendingId($prefix = '') {
$time = time(); // 当前秒级时间戳
$micro = microtime(true) * 1000000; // 微秒级时间戳
$uniqid = uniqid(); // 基于微时间的唯一ID
// 组合
$id = $prefix . $time . '-' .
str_pad($micro % 1000000, 6, '0', STR_PAD_LEFT) . '-' .
substr($uniqid, -8);
return $id;
}
高并发下基于 Redis 的实现
如果需要分布式高并发支持:
<?php
/**
* Redis 自增生成趋势ID
*/
class RedisTrendId {
private $redis;
public function __construct($redis) {
$this->redis = $redis;
}
public function nextId($key, $prefix = '') {
// 用当前时间戳作为Redis key的一部分,保证趋势性
$today = date('Ymd'); // 每天一个计数器,或按小时/分钟
// 原子自增
$sequence = $this->redis->incr("id_gen:{$key}:{$today}");
// 设置过期时间(避免无限增长)
if ($sequence == 1) {
$this->redis->expire("id_gen:{$key}:{$today}", 2 * 86400);
}
// 组合:日期+序列号
return $prefix . $today . '-' . str_pad($sequence, 6, '0', STR_PAD_LEFT);
}
}
推荐选择
| 场景 | 推荐方案 |
|---|---|
| 数据库主键 | 雪花算法(方案1) |
| API响应ID | 简单趋势ID(方案4) |
| 用户可读 | 带时间戳字符串(方案2) |
| 分布式系统 | Redis实现(方案5) |
| 日志追踪 | 微秒+随机(方案3) |
简单场景最佳实践:
$uniqueId = uniqid('prefix_', true);
// 会生成类似:prefix_65ab1234c5d6e7.23456789
// 包含了微秒时间戳和随机性,且趋势递增
这些方案都保证了唯一性,并且ID具有趋势递增的特性,便于数据库索引优化,您根据具体需求选择最适合的方案即可。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播