PHP 8.2 大更新
PHP 官方在前不久发布了 PHP 8.2 的大更新,我粗浅地看了一下基本上没啥太过出彩的更新,基本上也就是常规的写 Class
比较方便了,然后支持了一些新的特性了,新增了一些不会用到的函数并且淘汰了一些也是不会用到的函数。不过这个随机数生成器还是让我比较感兴趣的,所以来说一下。
首先我们参考这次更新的网站可知,PHP 这次更新的随机数生成器分成两个部分,一个叫做 Engine
(引擎),另外一个叫做 Randomizer
(随机器),但理解起来就是一个核心一个壳就行。引擎有四个不同的引擎,分别是 Secure
(默认的),Mt19937
, PcgOneseq128XslRr64
以及 Xoshiro256StarStar
,这几个引擎有啥不同就留给你们自己体会了。
具体实现
首先那必定是要先 use
一下的,我们这里用官方的 Xoshiro256StarStar
为例:
use Random\Engine\Xoshiro256StarStar;
use Random\Randomizer;
引用完了之后我们就可以调用了,首先我们先来初始化一下我们的核心,核心需要传入的是经过 SHA256 加密哈希后的种子:
$RndBluePrint = new Xoshiro256StarStar(
hash("sha256", "This is the seed to be used", true)
);
接着官方这里会用到 Fiber 进行多个随机数的运算,至于 Fiber 是 PHP 8.1 新增的东西,详细的可以回去看 《PHP 8.1 使用 Fiber 实现伪多线程操作》,我们先初始化一下 Fiber 池,初始化完成之后我们就要开始添加我们的 Fiber 了。
我们每次添加 Fiber 的时候,我们都先复制一下我们的核心,然后命令我们的核心 jump
一下,按照官方的文档,这一 jump
就是往前 $2^{128}$ 个随机数,可以保证我们生成数字的随机性。复制完了核心之后我们在 Fiber 所引用的 Function 里面创建一个 Randomizer
随机器,创建的时候记得传入我们的核心,那样才能得到对应的随机数,否则的话就是使用默认的核心。
创建完了随机器之后我们可以通过调用 getInt
来进行随机数的生成,按照官方的文档,我们要传入随机数的下界与上界,返回的就是一个在上界和下界之间的随机数了,最后我们将他们输出一下:
$fibers = [];
for($i = 0; $i < 8; $i++) {
$RndFiber = clone $RndBluePrint;
$RndBluePrint->jump();
$fibers[] = new Fiber(function() use ($RndFiber, $i) : void {
$randomizer = new Randomizer($RndFiber);
echo "{$i}: " . $randomizer->getInt(0, 1000) . ',' . $randomizer->getInt(0, 1000) . PHP_EOL;
});
}
最后,我们也是用随机数生成器来打乱一下 Fiber 池,我们可以使用 shuffleArray
来对一个数组进行打乱,打乱了之后逐个 Fiber 进行激活:
$randomizer = new Randomizer();
$fibers = $randomizer->shuffleArray($fibers);
foreach($fibers as $fiber) {
$fiber->start();
}
结果的验证
最后不妨来看一下我们生成的随机数是否一样,因为如果使用相同的核心以及相同的种子的话,生成的随机数也是一样的,或许因为打乱的 Fiber 的关系所以顺序不一样,但是每个 ID 的 Fiber 生成的随机数应该一样的:
5: 483,330
6: 424,713
0: 261,484
1: 700,395
2: 149,359
3: 685,449
7: 867,204
4: 665,715
完整代码
<?php
use Random\Engine\Xoshiro256StarStar;
use Random\Randomizer;
$RndBluePrint = new Xoshiro256StarStar(
hash("sha256", "This is the seed to be used", true)
);
$fibers = [];
for($i = 0; $i < 8; $i++) {
$RndFiber = clone $RndBluePrint;
$RndBluePrint->jump();
$fibers[] = new Fiber(function() use ($RndFiber, $i) : void {
$randomizer = new Randomizer($RndFiber);
echo "{$i}: " . $randomizer->getInt(0, 1000) . ',' . $randomizer->getInt(0, 1000) . PHP_EOL;
});
}
$randomizer = new Randomizer();
$fibers = $randomizer->shuffleArray($fibers);
foreach($fibers as $fiber) {
$fiber->start();
}