Random 统一随机数生成器(PHP 8.2+)
PHP 8.2 引入了全新的 Random\ 命名空间,提供了面向对象的随机数生成器(RNG)统一接口。新的 Random 扩展取代了旧的 rand()、srand()、mt_rand() 函数,提供了更好的安全性、可测试性和扩展性。
前置知识
阅读本节前,建议先了解:Math 数学函数、BC Math 任意精度
基础概念
新旧对比
php
<?php
declare(strict_types=1);
// 旧方式(已不推荐)
// rand() - 伪随机,不安全
// mt_rand() - Mersenne Twister,较快但不安全
// random_int() - PHP 7.0+ 密码学安全随机数
// PHP 8.2+ 新方式 - Random 扩展
use Random\Randomizer;
$randomizer = new Randomizer();
// 密码学安全的随机整数
echo $randomizer->getInt(1, 100) . PHP_EOL;
// 随机字节
echo bin2hex($randomizer->getBytes(16)) . PHP_EOL;Randomizer 类
基本用法
php
<?php
declare(strict_types=1);
use Random\Randomizer;
$randomizer = new Randomizer();
// 随机整数(包含边界)
$int = $randomizer->getInt(0, 100);
echo "随机整数 (0~100): {$int}" . PHP_EOL;
// 随机浮点数
$float = $randomizer->getFloat(0.0, 1.0);
echo "随机浮点: {$float}" . PHP_EOL;
// 随机字节
$bytes = $randomizer->getBytes(32);
echo "随机字节: " . bin2hex($bytes) . PHP_EOL;
// 从数组中随机选择
$items = ['苹果', '香蕉', '橙子', '葡萄'];
$random = $randomizer->pickArray($items);
echo "随机选择: {$random}" . PHP_EOL;
// 打乱字符串(PHP 8.3+)
$shuffled = $randomizer->shuffleBytes('hello world');
echo "打乱字符串: {$shuffled}" . PHP_EOL;获取随机浮点数
php
<?php
declare(strict_types=1);
use Random\Randomizer;
$randomizer = new Randomizer();
// getFloat(min, max) - 返回闭区间 [min, max] 内的随机浮点数
echo $randomizer->getFloat(0, 1) . PHP_EOL;
echo $randomizer->getFloat(1, 100) . PHP_EOL;
// 获取指定精度的浮点数
$float = $randomizer->getFloat(0, 1000000, \Random\IntervalBoundary::ClosedOpen);生成随机字符串
php
<?php
declare(strict_types=1);
use Random\Randomizer;
class RandomStringGenerator
{
private Randomizer $randomizer;
public function __construct()
{
$this->randomizer = new Randomizer();
}
/**
* 生成随机字符串
*/
public function generate(
int $length,
string $charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
): string {
$charsetLength = strlen($charset);
$result = '';
for ($i = 0; $i < $length; $i++) {
$index = $this->randomizer->getInt(0, $charsetLength - 1);
$result .= $charset[$index];
}
return $result;
}
/**
* 生成安全 Token
*/
public function token(int $length = 32): string
{
return bin2hex($this->randomizer->getBytes($length));
}
/**
* 生成密码
*/
public function password(int $length = 16): string
{
$lower = 'abcdefghijklmnopqrstuvwxyz';
$upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$digits = '0123456789';
$symbols = '!@#$%^&*()_+-=';
$charset = $lower . $upper . $digits . $symbols;
$password = $this->generate($length, $charset);
// 确保包含每种字符
$password[0] = $lower[$this->randomizer->getInt(0, strlen($lower) - 1)];
$password[1] = $upper[$this->randomizer->getInt(0, strlen($upper) - 1)];
$password[2] = $digits[$this->randomizer->getInt(0, strlen($digits) - 1)];
$password[3] = $symbols[$this->randomizer->getInt(0, strlen($symbols) - 1)];
return $password;
}
/**
* 生成 UUID v4
*/
public function uuid(): string
{
$data = $this->randomizer->getBytes(16);
// 设置版本号 (4) 和变体位
$data[6] = chr(ord($data[6]) & 0x0f | 0x40);
$data[8] = chr(ord($data[8]) & 0x3f | 0x80);
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
}
$gen = new RandomStringGenerator();
echo "随机字符串: " . $gen->generate(20) . PHP_EOL;
echo "Token: " . $gen->token(32) . PHP_EOL;
echo "密码: " . $gen->password(16) . PHP_EOL;
echo "UUID: " . $gen->uuid() . PHP_EOL;引擎(Engine)
可用引擎
php
<?php
declare(strict_types=1);
use Random\Engine;
use Random\Randomizer;
// Mersenne Twister(快速,不安全)
$mtEngine = new Engine\Mt19937(1234); // 可指定种子
$randomizer = new Randomizer($mtEngine);
echo $randomizer->getInt(1, 100) . PHP_EOL;
// Xorshift 128+(快速,不安全)
$xorEngine = new Engine\XorShift128Plus(5678);
$randomizer = new Randomizer($xorEngine);
// PCG64(快速,较好统计特性)
$pcgEngine = new Engine\PcgOneseq128XslRr64();
$randomizer = new Randomizer($pcgEngine);
// Secure(密码学安全,PHP 8.2+)
$secureEngine = new Engine\Secure();
$randomizer = new Randomizer($secureEngine);
// 从系统源生成(密码学安全)
$randomizer = new Randomizer(); // 默认使用 Secure 引擎可种子引擎(可重现)
php
<?php
declare(strict_types=1);
use Random\Engine\Mt19937;
use Random\Randomizer;
// 使用固定种子,结果可重现
$engine1 = new Mt19937(42);
$engine2 = new Mt19937(42);
$r1 = new Randomizer($engine1);
$r2 = new Randomizer($engine2);
// 两者生成相同的随机序列
for ($i = 0; $i < 5; $i++) {
echo "R1: " . $r1->getInt(1, 100) . ", R2: " . $r2->getInt(1, 100) . PHP_EOL;
}序列化引擎
php
<?php
declare(strict_types=1);
use Random\Engine\Mt19937;
use Random\Randomizer;
// 序列化引擎状态
$engine = new Mt19937(42);
$randomizer = new Randomizer($engine);
// 生成一些随机数
echo $randomizer->getInt(1, 100) . PHP_EOL;
// 序列化当前状态
$serialized = serialize($engine);
echo "序列化: " . $serialized . PHP_EOL;
// 反序列化恢复状态
$restored = unserialize($serialized);
$randomizer2 = new Randomizer($restored);
echo "恢复后: " . $randomizer2->getInt(1, 100) . PHP_EOL;测试中的使用
可预测的随机数(单元测试)
php
<?php
declare(strict_types=1);
use Random\Engine\Mt19937;
use Random\Randomizer;
class Lottery
{
public function __construct(private readonly Randomizer $randomizer = new Randomizer()) {}
public function draw(array $participants, int $winners): array
{
$shuffled = $participants;
for ($i = count($shuffled) - 1; $i > 0; $i--) {
$j = $this->randomizer->getInt(0, $i);
[$shuffled[$i], $shuffled[$j]] = [$shuffled[$j], $shuffled[$i]];
}
return array_slice($shuffled, 0, $winners);
}
}
// 单元测试中使用固定种子
$testEngine = new Mt19937(42);
$lottery = new Lottery(new Randomizer($testEngine));
$winners = $lottery->draw(['Alice', 'Bob', 'Charlie', 'Dave', 'Eve'], 2);
echo "中奖者: " . implode(', ', $winners) . PHP_EOL;
// 每次运行结果相同,便于断言旧 API 兼容
php
<?php
declare(strict_types=1);
// random_int() - 密码学安全随机整数(PHP 7.0+)
$int = random_int(1, 100);
// random_bytes() - 密码学安全随机字节(PHP 7.0+)
$bytes = random_bytes(16);
echo bin2hex($bytes) . PHP_EOL;
// 这些函数在新 Random 扩展中仍然可用且推荐注意事项
Randomizer默认使用Secure引擎(密码学安全)- 单元测试使用固定种子的
Mt19937引擎 - 不要使用
rand()和mt_srand(),已被弃用 Random\Engine\Secure基于 CSPRNG
下一节
继续学习:cURL 详解