PHP+TCPDF成绩表生成:数组键匹配与单元格对齐异常问题
问题分析与解决方案
我看出来你的核心问题了——当前的循环匹配逻辑完全搞反了方向,而且没建立科目ID和分数的直接关联,导致分数放错了对应的单元格位置。
原代码的问题根源
- 匹配逻辑颠倒:你遍历应考科目的数量时,却用
$subjectIDs[$i](已考科目数组的第i个元素)去检查是否在应考科目数组里——这本身就是冗余的(已考科目肯定是应考科目的子集),而且当已考科目数量少于应考科目时,$subjectIDs[$i]会取到null,完全无法对应当前遍历的应考科目。 - 无关联映射:没有把科目ID和分数绑定成关联数组,只能依赖索引位置匹配,这在已考、应考科目数量不一致时必然出错。
修正方案
我们需要先把已考科目和对应的分数整合成关联数组(键为科目ID,值为分数),然后遍历所有应考科目,逐个检查该科目是否存在于关联数组中:存在则输出分数,不存在则输出占位符。
修改后的完整代码片段
foreach ($results_ as $row) { $smarks = $row['mar']; $integerIDs = explode(',', $smarks); asort($integerIDs); $subjects_ = $row['subjects_']; $subjectIDs = explode(',', $subjects_); asort($subjectIDs); // 关键修改:将科目ID与对应分数绑定为关联数组 $scoreMap = []; foreach ($subjectIDs as $index => $subjectId) { $scoreMap[$subjectId] = $integerIDs[$index]; } $subject_count = count($subjectIDs); $average = round($row['m'] / $subject_count, 2); $total_subject_marks = $exam_out_of * $subject_count; $SubjectPercentage = round(($row['m'] / $total_subject_marks) * 100); // 学生基本信息输出部分保持不变 $pdf->Cell($width_cell[5], 7, $row['s'], $border=1,$ln=0,'C',$fill=$fill, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='R'); $pdf->Cell($width_cell[2], 7, $row['FirstName'] . " " . $row['OtherNames'] . " " . $row['LastName'], $border=1,$ln=0,'L',$fill=$fill, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='R'); $pdf->Cell($width_cell[4], 7, $row['RollId'],$border=1,$ln=0,'L',$fill=$fill, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='R'); // 关键修改:遍历所有应考科目,精准匹配分数 $allSubjects = getAllSubjects($class_id); foreach ($allSubjects as $subjectId) { if (isset($scoreMap[$subjectId])) { // 存在该科目分数,输出分数值 $pdf->Cell($width_cell[4], 7, $scoreMap[$subjectId] ,$border=1,$ln=0,'C',$fill=true, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='R'); } else { // 未考该科目,输出占位符 $pdf->Cell($width_cell[4], 7, "_" ,$border=1,$ln=0,'C',$fill=true, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='R'); } } // 总分、平均分等后续输出部分保持不变 $pdf->setX(238); $pdf->Cell($width_cell[4], 7, $row['m'], $border=1,$ln=0,'C',$fill=$fill, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='R'); $pdf->Cell($width_cell[4], 7, $average , $border=1,$ln=0,'C',$fill=$fill, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='R'); $pdf->Cell($width_cell[4], 7, $exam_out_of, $border=1,$ln=0,'C',$fill=true, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='R'); $SubjectPercentages = round($SubjectPercentage); if($SubjectPercentages >= 96){ $grade = "EX"; }elseif ($SubjectPercentages >= 86 && $SubjectPercentages <= 95) { $grade = "VG"; }elseif($SubjectPercentages >=70 && $SubjectPercentages <= 85 ){ $grade = "G"; }elseif ($SubjectPercentages >= 50 && $SubjectPercentages <= 69) { $grade = "P"; }else { $grade = "F"; } $pdf->Cell($width_cell[10], 7, $grade ,$border=1,$ln=1,'C',$fill=true, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='R'); $fill = !$fill; $cnt = $cnt + 1; }
额外优化建议
- 缓存应考科目列表:把
getAllSubjects($class_id)的结果在循环开始前提前获取并缓存(比如$allSubjects = getAllSubjects($class_id);),避免循环内多次调用函数/查询数据库,提升性能。 - 统一数据类型:如果
$subjectIDs里的科目ID是字符串类型,而getAllSubjects返回的是整数类型,记得用(int)$subjectId统一类型,避免因类型不匹配导致判断错误。
内容的提问来源于stack exchange,提问作者salim
相关产品推荐
相关产品推荐

