PHP生成Housie/Bingo票证时6张组数字唯一规则实现500报错问题
问题原因分析
- 参数不匹配致命错误
你定义fillEmptyColumn时只声明了3个入参,但是调用时传入了5个参数$this->fillEmptyColumn($k, $ticket_array, $batch_numbers, $batch, $game_id);,PHP会直接抛出参数数量不符的致命错误,这是触发500的直接原因之一。 - 已用数字未回滚导致名额浪费
你在fillEmptyColumn中把其他列已填充的数字设为0补到空列,但这个被删掉的数字已经被加入batch_numbers数组,相当于占用了批次的数字名额但实际未使用,批次进行到后期必然出现数字不够用的情况。 - 无限递归栈溢出
generateRandomColumnNumber用递归实现去重,当对应列的可用数字全部被batch_numbers占用时,函数会无限递归调用自身,直到PHP栈内存耗尽,直接触发500错误。 - 位置随机选择逻辑不合理
完全随机选每行5个位置的方式,既不能保证单张票每列至少1个数字(需要后续补空),也不能保证6张票的每列总需求不超过该列的数字上限(比如第一列只有9个数字,随机选可能出现6张票第一列要占10个位置的情况),必然会出现数字分配冲突。
修复方案
第一步:修复参数与数字回滚逻辑
先保证调用fillEmptyColumn的参数数量和定义一致,同时补充被删除数字的回滚逻辑,避免数字名额浪费:
// 调用时删掉多余的$batch、$game_id参数 $modified_array = $this->fillEmptyColumn($k, $ticket_array, $batch_numbers);
// 修改fillEmptyColumn的内部逻辑,其他分支同理补充回滚操作 if($ticket_array[0][$i] != 0 && $ticket_array[1][$i] != 0 && $ticket_array[2][$i] != 0){ $del_num = $ticket_array[2][$i]; // 从已用数组中移除被删掉的数字,释放名额 $batch_numbers = array_diff($batch_numbers, [$del_num]); $new_number = $this->generateRandomColumnNumber($column, $batch_numbers); $ticket_array[2][$i] = 0; $ticket_array[2][$column] = $new_number; array_push($batch_numbers, $new_number); break; }
第二步:替换递归去重逻辑,避免栈溢出
不要用递归实现数字去重,提前为每个批次生成各列的打乱数字池,用的时候直接取,完全避免无效判断和递归栈溢出问题:
// reset批次时先初始化各列的数字池 if($reset){ $batch_numbers = array(); // 初始化各列数字池并打乱 $this->column_pools = []; for($col=0;$col<9;$col++){ if($col == 0) $nums = range(1,9); elseif($col ==8) $nums = range(80,90); else $nums = range($col*10, ($col+1)*10 -1); shuffle($nums); $this->column_pools[$col] = $nums; } $reset = false; $ticket_set++; } // 修改generateRandomColumnNumber直接从对应池子取数,无需递归 protected function generateRandomColumnNumber($column) { return array_pop($this->column_pools[$column]); }
第三步:优化位置选择逻辑(可选但推荐)
提前为每张票确定列的填充数量,保证单张票每列至少1个,每行正好5个,就可以完全避免后续补空操作,大幅降低冲突概率:每张票9列每列至少1个,共9个填充位,剩下6个额外填充位随机分配到各列即可,符合3行共15个填充位的要求。
内容的提问来源于stack exchange,提问作者Jyotishmoy
相关产品推荐
相关产品推荐

