PHP 產生隨機數常用 mt_rand() (Mersenne Twister,速度快、週期長) 與 random_int() (密碼學安全)。需「指定範圍、多個、不重複」時,陣列打亂法 效能最佳、程式碼最簡潔。本文比較三種方法、提供封裝函式、解析密碼學安全需求與效能基準。
| 方法 | 程式碼複雜度 | 效能 (大範圍/大數量) | 記憶體 | 適用場景 |
|---|---|---|---|---|
| 1. range + shuffle + array_slice (推薦) | 極低 | O(N) 線性,極快 | O(N) 建立完整陣列 | 範圍 ≤ 100 萬、需不重複、一般用途 |
| 2. mt_rand + in_array/isset 去重 | 中 | 隨機碰撞隨數量增大劇烈下降 | O(K) 僅存結果 | 範圍極大 (億級)、需少量 (≤100) 不重複 |
| 3. random_int + 去重 (密碼學安全) | 中 | 較慢 (系統熵池) | O(K) | Token、API Key、加密鹽、安全敏感場景 |
<?php
/**
* 取得指定範圍內 $count 個不重複隨機整數
* @param int $min 最小值 (含)
* @param int $max 最大值 (含)
* @param int $count 需要個數
* @return int[]
* @throws InvalidArgumentException 範圍不足
*/
function randomUniqueInts(int $min, int $max, int $count): array {
if ($count > ($max - $min + 1)) {
throw new InvalidArgumentException("請求個數 $count 超過範圍大小 " . ($max - $min + 1));
}
$pool = range($min, $max); // 建立 [min, max] 陣列
shuffle($pool); // 原地打亂 (Fisher-Yates)
return array_slice($pool, 0, $count); // 取前 $count 個
}
// 使用範例
$numbers = randomUniqueInts(1, 100, 10); // 1-100 間 10 個不重複數
print_r($numbers); // [42, 17, 89, 3, 56, 71, 2, 94, 11, 63]
function randomUniqueFromArray(array $pool, int $count): array {
if ($count > count($pool)) throw new InvalidArgumentException('...');
shuffle($pool);
return array_slice($pool, 0, $count);
}
// 字串池
$codes = randomUniqueFromArray(['A','B','C','D','E','F'], 3);
// 浮點數 (需自行建立池)
$floats = randomUniqueFromArray(array_map(fn($i)=>$i/100, range(1, 100)), 5);
// 單一安全隨機整數
$secure = random_int(1, 100); // 含邊界
// 多個不重複安全隨機數 (範圍不大時)
$pool = range(1, 100);
shuffle($pool); // shuffle 內部用 php_rand() 非密碼學安全!
// 真正安全需自行實作 Fisher-Yates 用 random_int()
function secureShuffle(array &$arr): void {
for ($i = count($arr) - 1; $i > 0; $i--) {
$j = random_int(0, $i);
[$arr[$i], $arr[$j]] = [$arr[$j], $arr[$i]];
}
}
secureShuffle($pool);
$secureUnique = array_slice($pool, 0, 10);
mt_rand/shuffle 足夠// range+shuffle+slice: ~8ms, 記憶體 ~8MB // mt_rand+isset去重: ~45ms (碰撞率低時) // random_int+secureShuffle: ~120ms
結論:一般業務 range+shuffle+slice 最優;安全場景自行實作 Fisher-Yates + random_int。
| 錯誤程式碼 | 問題 | 修正 |
|---|---|---|
mt_rand(1, 100) 重複呼叫 10 次 | 極高機率重複 | 用 shuffle 法或去重迴圈 |
array_rand($arr, 10) | PHP 7.1+ 修復偏向性,但不保證不重複 (文檔明確說明) | 用 shuffle+slice |
shuffle($arr); $arr[0] 取單一 | 過度殺傷、修改原陣列 | 單一用 $arr[mt_rand(0, count($arr)-1)] 或 $arr[array_rand($arr)] |
range($min,$max) + shuffle() + array_slice(),封裝函式複用。random_int() + 自製 Fisher-Yates shuffle。mt_rand() + isset($seen[$num]) 去重迴圈。$count <= $max-$min+1,避免無限迴圈/例外。相關專題:《PHP 數學運算技巧總結》、《PHP 程序設計算法總結》。