Laravel遍历Prize集合分配唯一Ticket出现重复ID的原因与解法
问题产生原因
- PHP闭包默认使用值传递引入外部变量,你的代码中
use($tickets)是将外部$tickets集合拷贝了一份传入闭包作用域,闭包内对$tickets的修改只会作用于当前闭包内的副本,不会影响外部的原始奖券集合。所以每次循环抽奖都是从完整的初始奖券集合中抽取,自然会出现重复分配的问题。 - Laravel集合的
except()方法是返回新的集合实例,不会修改原集合本身,就算你拿到的是原集合的引用,直接赋值给局部变量也需要对应修改外部变量。 - 额外小问题:原查询写法
Prize::all()->limit(5)->get()存在性能浪费,all()方法会直接执行查询返回全表数据的集合,后续的limit()是集合方法而非查询构造器方法,正确写法应该是先调用limit()再执行get(),即Prize::limit(5)->get(),Tickets的查询同理。
正确实现代码
只要给闭包引入的$tickets加上引用符号&,让闭包内的修改直接作用于外部的原始集合即可:
// 优化查询,直接在SQL层面限制数量 $prizes = Prize::limit(5)->get(); $tickets = Tickets::limit(5)->get(); $prizes->each(function ($prize, $key) use(&$tickets) { // 加&变为引用传递 $winner = $tickets->random(); $prize->ticket_winner_id = $winner->id; // 如果需要持久化到数据库,这里加一行 $prize->save(); $tickets = $tickets->except($winner->id); });
如果你不习惯闭包引用的写法,也可以用普通foreach循环实现,逻辑更直观:
$prizes = Prize::limit(5)->get(); $tickets = Tickets::limit(5)->get(); foreach ($prizes as $prize) { $winner = $tickets->random(); $prize->ticket_winner_id = $winner->id; // $prize->save(); $tickets = $tickets->except($winner->id); }
内容的提问来源于stack exchange,提问作者InvalidSyntax
相关产品推荐
相关产品推荐

