首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 產生指定範圍多個不重複隨機數:mt_rand、shuffle、range 三種方法比較與最佳實踐

     編輯:PHP 綜合知識

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);

密碼學安全隨機數:random_int / random_bytes (PHP 7+)

// 單一安全隨機整數
$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);

何時必須用密碼學安全?

  • API Token、Session ID、CSRF Token、重設密碼 Token
  • 加密金鑰、IV、鹽值
  • 抽獎、博弈、任何涉及利益分配的隨機
  • 一般顯示順序打亂、測試資料、遊戲 NPC 行為 → mt_rand/shuffle 足夠

效能基準參考 (PHP 8.1, 1-100萬範圍取 1萬個)

// 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)]

總結

  1. 一般不重複隨機數 → range($min,$max) + shuffle() + array_slice(),封裝函式複用。
  2. 安全敏感 → random_int() + 自製 Fisher-Yates shuffle。
  3. 超大範圍少量需求 → mt_rand() + isset($seen[$num]) 去重迴圈。
  4. 永遠驗證 $count <= $max-$min+1,避免無限迴圈/例外。

相關專題:《PHP 數學運算技巧總結》、《PHP 程序設計算法總結》。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved