你可以以一种干净易读的方式完成此操作,而无需使用循环、字符串连接或多次调用rand()等不干净/昂贵的方法。此外,最好使用mt_rand():
function createRandomString($length)
{
$random = mt_rand(0, (1 << ($length << 2)) - 1);
return dechex($random);
}
如果您需要字符串在任何情况下具有精确的长度,请使用零填充十六进制数:
function createRandomString($length)
{
$random = mt_rand(0, (1 << ($length << 2)) - 1);
$number = dechex($random);
return str_pad($number, $length, '0', STR_PAD_LEFT);
}
"理论上的缺陷是,你受到PHP能力的限制 - 但这更多是一种哲学问题;) 让我们无论如何都来看看它:"
- PHP在表示十六进制数字时有限制。在32位系统上,这至少应该是
$length <= 8
,而PHP的限制应该是4,294,967,295。
- PHP的随机数生成器也有最大值。对于
mt_rand()
,在32位系统上至少应该是2,147,483,647。
- 因此,你理论上只能使用2,147,483,647个ID。
回到主题 - 直觉上的do { (generate ID) } while { (id is not uniqe) } (insert id)
有一个缺点和一个可能的缺陷,这可能会让你直接陷入黑暗中...
"
缺点: 验证是悲观的。像这样做总是需要在数据库中进行检查。拥有足够的键空间(例如,对于您的10k条目长度为5),很少会导致碰撞,因为只尝试存储数据并仅在唯一键错误的情况下重试可能会比较少消耗资源。
缺陷: 用户A检索到一个尚未占用的ID进行验证。然后代码将尝试插入数据。但与此同时,
用户B进入了相同的循环,并不幸地检索到相同的随机数,因为
用户A尚未存储,而此ID仍然是自由的。现在系统要么存储
用户B,要么存储
用户A,当尝试存储第二个用户时,已经有另一个用户同时使用相同的ID。
你需要在任何情况下处理该异常,并使用新创建的ID重新尝试插入。在保留悲观检查循环的同时添加此功能会导致代码相当丑陋且难以理解。
幸运的是,解决此问题的方法与缺点的解决方案相同:首先尝试存储数据。如果出现唯一键错误,请使用新的ID重试。
Random::alphaLowercaseString(6)
来获取,或者根据你的需要选择长度为 8 或 10。 - caw