一個有關PHP隨機數的坑...


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/rnd.php
    echo 
done

連續跑100次,測試通過。

 



其實。。。

前例中的代碼會報告一個

 

PHP Notice: A non well formed numeric value encountered

 

警告。但是如果腳本是跑在服務或者后台進程中,則可能不容易發現問題。


或者。。。

PHP中已經有了一個mt_rand()的函數用來替換古老的rand,可以自動播種並且效率比rand高四倍。。。好吧,看來研究舊有問題和學習新鮮知識一個都不能少。。。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM