跳转到主要内容

什么是 Lottery 类

Illuminate\Support\Lottery 是可以用流畅 API 描述基于概率操作的工具类。它可以简洁地表达「每 100 个请求执行一次」「只对部分请求记录详细日志」这类模式。
实现位于 src/Illuminate/Support/Lottery.php。Laravel 也在框架内部使用它,例如 Session GC、缓存锁的清理。

基本用法

用整数比率指定概率

Lottery::odds($chances, $outOf) 指定「outOf次中中outOf 次中中 chances 次」的概率。

用小数指定概率

省略 $outOf 而传入 0.01.0 的小数时,会直接作为概率使用。
以小数指定时,值超过 1.0 会抛出 RuntimeException

无回调时返回布尔值

若未设置 winner / loser,choose() 会返回:中奖时 true,未中时 false

多次执行

choose($times) 传入次数会返回结果数组。

作为 Callable 传入

Lottery 实例实现了 __invoke,因此可以直接作为 callable 传入。

实战用例

1. 缓存清理(每 100 次执行一次)

对于删除过期记录这类不需要每次都执行的维护处理非常合适。

2. 遥测采样(只对部分请求记录详细日志)

若对所有请求记日志成本过高,可以用它做采样。

3. A/B 测试式的行为切换

概率性地把用户分配到两条不同的代码路径。

4. 作为 Scheduler 的辅助随机执行定时任务

在多台服务器中避免重复执行的同时随机执行某个任务时可以使用。

Laravel 框架内部的概率模式

Laravel 在框架内部广泛使用了概率式维护处理。其中一些实现是在 Lottery 类被加入之前编写的,因此直接使用 random_int(),但思路是一致的。
1

Session:垃圾回收

Illuminate\Session\Middleware\StartSession::configHitsLottery() 使用 config/session.php 中的 lottery 配置,通过 random_int 概率判定并执行 GC。
2

DatabaseLock:清理过期锁

Illuminate\Cache\DatabaseLock::acquire() 在每次获取锁时以相同比率清理过期锁。
3

DB::whenQueryingForLongerThan — 传入 Lottery 类的示例

Lottery 实例可作为 callable 传入,可直接用于慢查询检测回调。
Session 与 DatabaseLock 直接使用 random_int(),而 Lottery 类的优势在于测试时可以通过 alwaysWin() / alwaysLose() / fix() 控制结果。在包开发中选用 Lottery 类可提高可测试性。

测试时的用法

对包含随机性的代码测试,可使用 Lottery 提供的测试用 API。

Lottery::alwaysWin() — 始终中奖

Lottery::alwaysLose() — 始终未中

Lottery::fix() — 用序列固定结果

可用 true/false 数组控制多次调用的结果。
alwaysWin() / alwaysLose() / fix() 会改变全局静态属性。请务必在测试的 tearDown() 中调用 Lottery::determineResultNormally()

Lottery::setResultFactory() — 注入自定义 Factory

如需更细粒度的控制,可使用自定义 Factory。

在包开发中的应用

在 Service Provider 中注册

在包 Service Provider 中集成维护处理时,可用 Lottery 分散负载。

从配置读取赔率

允许通过配置文件调整概率,方便用户微调。

在 Middleware 中做采样

API 参考

相关页面

Macroable trait

学习向既有类添加新方法的扩展模式。

Conditionable trait

学习基于 when() / unless() 的条件分支链式设计。
最后修改于 2026年7月18日