You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP+TCPDF成绩表生成:数组键匹配与单元格对齐异常问题

问题分析与解决方案

我看出来你的核心问题了——当前的循环匹配逻辑完全搞反了方向,而且没建立科目ID和分数的直接关联,导致分数放错了对应的单元格位置。

原代码的问题根源

  1. 匹配逻辑颠倒:你遍历应考科目的数量时,却用$subjectIDs[$i](已考科目数组的第i个元素)去检查是否在应考科目数组里——这本身就是冗余的(已考科目肯定是应考科目的子集),而且当已考科目数量少于应考科目时,$subjectIDs[$i]会取到null,完全无法对应当前遍历的应考科目。
  2. 无关联映射:没有把科目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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 20:32:29