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高四倍。。。好吧,看來研究舊有問題和學習新鮮知識一個都不能少。。。