【PHP8.2】 PHP的随机数功能将进一步改善

有关PHP8.2中PHP随机数的改进的报道后来出现了一些问题和不足,因此提出了一个和这些问题有关的后续RFC来解决它们。

以下是关于随机扩展改进的相关RFC的介绍。
虽然有七个提案,但全部都被采纳了。

另外,由于此RFC是针对PHP8.2的,因此从2022年12月8日发布的PHP8.2版本起,已经可以使用了。

PHP RFC: 随机扩展改进

简介

在最近的Random Extension 5.x版本中,投票开始后出现了一些问题。

引擎实现还未完善。

在Random Extension中提供的原生随机数生成引擎的类没有使用final修饰符。
这意味着可以创建继承了原生类的子类,但正如上次的RFC所提到的那样,在用户自定义的引擎中,执行效率会低于原生类。
即使没有重写方法,这种效率降低也会成为一个问题。

由于扩展已经提供了Random\Engine接口,即使本地类变为final,使用此扩展也没有问题。

这是API设计的错误,应该将随机数引擎的本机实现设为final。

Random\SerializableEngine 没有用处。

Random\SerializableEngine是Serializable接口仍然存在时的残留物。
由于现在的PHP是通过存在__serialize()方法来判断是否可序列化,因此这个接口已经变得不再需要。

所以,我们将删除Random\SerializableEngine。

现在实现SerializableEngine的随机数引擎不再需要实现此功能,但不会影响其可序列化性的判断。

Random\Engine\CombinedLCG是低质量的。

Random\Engine\CombinedLCG是一个仅在lcg_value函数中使用的随机数引擎。
然而,这个算法是古老且品质低劣的。

为了保持lcg_value的值不变,将保留内部实现,但废除类,并且无法从外部使用。

在中文中没有array_rand()的等价函数。

在Randomizer中,没有与array_rand相对应的功能。
根据以前的RFC,这是有意为之。
但是,根据我的研究,由于array_rand在许多库中被广泛使用,所以在Randomizer中也应该可用。

在这种情况下,我们将添加一个Randomizer::pickArrayKeys(array $array, int $num): array方法。
虽然一开始array_rand(array $array, int $num = 1): int|string|array似乎不兼容,但是通过以下方法,我们可以得到相同的结果。

$array = ['foo', 'bar', 'baz'];

// これまで
mt_srand(1234, MT_RAND_PHP);
$single = array_rand($array); // 0
$multiple = array_rand($array, 2); // [1, 2]

// 今後
$engine = new Random\Engine\Mt19937(1234, MT_RAND_PHP);
$randomizer = new Random\Randomizer($engine);
$single = $randomizer->pickArrayKeys($array, 1)[0]; // 0
$multiple = $randomizer->pickArrayKeys($array, 2); // [1, 2]

“字符串”代表一个二进制.

在PHP中,字符串意味着二进制数据。
这在处理多字节字符串时会有问题,例如使用str_shuffle函数处理日语会变得混乱不堪。

因此,将与str_shuffle对应的方法Randomizer::shuffleString()更名为Randomizer::shuffleBytes()将更加合适。

引擎类的名称不够精确。

引擎类名存在歧义,需要改名以明确算法。
Random\Engine\PCG64 → Random\Engine\PcgOneseq128XslRr64
Random\Engine\MersenneTwister → Random\Engine\Mt19937

PCG 不是很有名。

尽管PCG算法具有优秀的随机性和性能,但与Xorshift相比,它的知名度远逊一筹。

为了避免由于对PCG不熟悉而选择使用MT19937,我们决定以前考虑过的Random\Engine\Xoshiro256StarStar作为备选方案进行额外实施。

建议

我们将就各个议题进行投票。

引擎实现并非最终版。

以18票赞成,1票反对的多数赞成通过了。

随机的\可序列化引擎是无用的。

以18票赞成、0票反对的赞成多数通过了。

Random\Engine\CombinedLCG 的质量很低。

以18票赞成、0票反对的多数赞成通过。

没有与array_rand()等同的函数。

以12票赞成、2票反对的多数通过了。

“字符串”意味着二进制。

以16票赞成、1票反对的多数赞成通过了。

引擎类名不准确

这项决议以14票赞成、1票反对的多数通过了。

PCG 不是很有名。

以13票赞成和1票反对的多数通过了此决议。

向后不兼容的更改 bù de

以下的类名将变为无效。

・随机\引擎\Mt19937
・随机\引擎\PcgOneseq128XslRr64
・随机\引擎\Xoshiro256StarStar

以下的课程名称将可供使用。

・随机引擎\组合线性同余发生器
・随机引擎\梅森旋转子
・随机引擎\PCG64
・随机可序列化引擎

提议的PHP版本

PHP8.2 can be expressed in Chinese as “PHP8.2 版本”

RFC影响

没有特别的事情。

贴片和测试

 

参考文献

 

印象

这个RFC会补充和修改关于乱数的最初RFC所遗漏的内容。

PHP内部在提案阶段通常是非常冷淡的,但一旦开始投票,就会突然变得热烈起来,这种坏习惯很常见,例如,创建traits中的常量的人曾经说过非常困扰的话。
(我感觉好像看到过更直接的说法,但是找不到了)

因此,关于Random Extension,似乎有一些建议提出,在投票开始后将其变为最终版本可能会更好,这导致了改进RFC的提案。

尽管在投票开始后依然有一些争议,但由于所有提案都通过了,因此从PHP8.2版本开始,我们已经可以使用它了。庆祝一下。

广告
将在 10 秒后关闭
bannerAds