一个有关PHP随机数的坑...

时间:2024-10-23 08:32:36

php中获取随机数的方法很简单,使用rand函数就可以了

int rand ( int $min , int $max )

一句调用就可以获得指定范围的随机数。但是大家都知道,计算机中使用的随机数实际是 伪随机数,一般来说,为了增加随机性,我们还会习惯在调用之前设置一下随机种子:

void srand ([ int $seed ] )

按照其他语言的习俗,会在 srand的参数里传递一个时间值,一般会传递当前时间的毫秒值或者微秒值进去。虽然从PHP4.2开始,调用rand的时候会自动调用srand,所以srand调用是一个并非必须的操作。


PHP中可以使用microtime()函数来获取随机数。于是,在一个一般性随机数需求场景下,我们就可以使用下述代码获取随机数了

<?php
    srand(microtime());
    echo rand(1, 25).PHP_EOL;
    echo rand(1, 25).PHP_EOL;
?>

执行代码,我们得到了两个随机数。看似不错,但是再次执行,却发现得到的随机数和上次的一模一样。

这是啥状况?我们明明已经设置srand种子为当前时间的毫秒值了。

查阅文档,才发现其中的问题,原来在不带参数的情况下,mircotime函数会以"msec sec" 的格式返回一个空格分隔的字符串,经过自动类型转换,srand实际得到的参数值是0,在固定随机种子的情况下,会得到固定的随机序列,因此每次执行脚本都会得到相同的随机数。

从PHP5开始,microtime增加了一个$get_as_float参数,通过传递true,可以让microtime返回一个当前毫秒的float值,由于返回值小数点之前是当前的秒值,因此对结果再乘以1000把小数点扩展到毫秒级别,这样就可以安全的获取随机数了:

<?php
    srand(microtime(true) * 1000);
    echo rand(1, 25).PHP_EOL;
    echo rand(1, 25).PHP_EOL;
?>

连续访问两次,得到了不同的随机数,再写一个bash脚本:

for i in $(seq 1 1 100)
do
    curl http://127.0.0.1/
    echo 
done
连续跑100次,测试通过。



其实。。。

前例中的代码会报告一个

PHP Notice: A non well formed numeric value encountered

警告。但是如果脚本是跑在服务或者后台进程中,则可能不容易发现问题。


或者。。。

PHP中已经有了一个mt_rand()的函数用来替换古老的rand,可以自动播种并且效率比rand高四倍。。。好吧,看来研究旧有问题和学习新鲜知识一个都不能少。。。