將獎項按機率展開為陣列元素,再用 shuffle() 打亂順序,最後 array_rand() 取一個。簡單直觀,適合獎項固定、總量可控的場景。
<?php
/**
* 抽獎函數
* @param int $total 總樣本基數,越大機率越精確
* @return mixed 中獎等級或「謝謝惠顧」
*/
function getReward($total = 1000) {
// 定義各獎項機率(百分比)
$win1 = floor((0.12 * $total) / 100); // 一等獎 0.12%
$win2 = floor((3 * $total) / 100); // 二等獎 3%
$win3 = floor((12 * $total) / 100); // 三等獎 12%
$other = $total - $win1 - $win2 - $win3; // 未中獎
$pool = array();
// 依機率填充獎池
for ($i = 0; $i < $win1; $i++) { $pool[] = 1; }
for ($i = 0; $i < $win2; $i++) { $pool[] = 2; }
for ($i = 0; $i < $win3; $i++) { $pool[] = 3; }
for ($i = 0; $i < $other; $i++) { $pool[] = '謝謝惠顧'; }
// 打亂並抽取
shuffle($pool);
return $pool[array_rand($pool)];
}
// 使用範例
$data = getReward();
echo "抽獎結果:$data";
?>
<?php
$stats = array(1 => 0, 2 => 0, 3 => 0, '謝謝惠顧' => 0);
$rounds = 100000;
for ($i = 0; $i < $rounds; $i++) {
$stats[getReward()]++;
}
foreach ($stats as $k => $v) {
echo "$k: $v (" . round($v/$rounds*100, 2) . "%)\n";
}
?>
輸出會非常接近理論值(0.12%、3%、12%、84.88%)。
| 優點 | 缺點 |
|---|---|
| 代碼極簡,無需引入第三方庫 | 記憶體佔用隨 $total 線性增長 |
| 機率直觀,修改百分比即時生效 | $total 過大(>100萬)會明顯拖慢效能 |
| 適合獎項固定、並發不極高的活動 | 不支援動態權重(如庫存扣減即時調整機率) |
<?php
function getRewardWeighted(array $prizes) {
// $prizes = ['一等獎' => 0.12, '二等獎' => 3, '三等獎' => 12, '謝謝惠顧' => 84.88];
$total = array_sum($prizes);
$rand = mt_rand(1, $total * 10000) / 10000; // 放大 10000 倍避免浮點誤差
$accum = 0;
foreach ($prizes as $name => $weight) {
$accum += $weight;
if ($rand <= $accum) return $name;
}
return '謝謝惠顧'; // 理論不會走到這
}
?>
優點:常數記憶體、支援動態權重、效能穩定。生產環境高併發抽獎建議採用此法或 Redis Lua 腳本保證原子性。
session 或 Redis 記錄用戶抽獎次數,防刷