PHPExcel非常慢 - 改进的方法?

2022-08-30 10:31:58

我正在使用PHPExcel在.xlsx生成报告。在使用小数据集(数十行,3张纸)的初始测试阶段,这是可以的,但是现在,当将其用于每张纸中超过500行的实际生产数据时,它变得非常慢。生成一个文件需要 48 秒,当运行一个包含更多信息的报告时,整个失败与 .有时它位于另一个PHPExcel文件中,所以我怀疑确切的位置是否相关。Fatal error: Maximum execution time of 30 seconds exceeded in PHPExcel/Worksheet.php on line 1041

理想情况下,如果可能的话,我想以某种方式加快速度。如果不是,则至少增加此脚本的执行限制。

到目前为止,我看到的唯一建议是在范围中设置样式,而不是单个单元格。不幸的是,我已经在范围内做了我的造型,它也相当小。还有其他建议吗?


答案 1

它是否正在填充工作表?还是储蓄?你觉得太慢了?

如何用数据填充电子表格?

  • 使用该方法比填充每个单独的单元格更有效,尤其是在使用高级值绑定器自动设置单元格数据类型时。fromArray()
  • 如果要为工作表中的每个单元格设置值,请使用

    $objPHPExcel->getActiveSheet()->setCellValue('A1',$x);
    $objPHPExcel->getActiveSheet()->setCellValue('B1',$y);
    

    $sheet = $objPHPExcel->getActiveSheet();
    $sheet->setCellValue('A1',$x);
    $sheet->setCellValue('B1',$y);
    

    因此,您只能访问该方法一次;或者利用流畅的界面设置多个单元格,只需一次调用getActiveSheet()$objPHPExcel->getActiveSheet()

    $objPHPExcel->getActiveSheet()->setCellValue('A1',$x)
                                  ->setCellValue('B1',$y);
    

您已经对将样式应用于单元格区域进行了评论:

  • 您还可以选择使用一次性设置各种样式设置。applyFromArray()
  • 如果可以将样式应用于列或行,而不是简单地应用于区域,则效率要高得多

如果您在工作簿中使用公式,则在保存时:

  • $objWriter->setPreCalculateFormulas(false)
    

    以禁用在 PHPExcel 本身中计算公式。

这些只是帮助提高性能的一些提示,论坛线程中还有很多建议。它们不一定都有帮助,这在很大程度上取决于您的特定工作簿来提供任何绝对值,但您应该能够提高这种缓慢的速度。即使是我用于开发的小笔记本,也可以比生产服务器更快地编写 3 个工作表、20 列、2,000 行 Excel 2007 文件。

编辑

如果可以简单地提高PHPExcel本身的速度,我早就这样做了。事实上,我一直在进行性能测试,看看如何提高它的速度。如果你想要比PHPExcel本身更快的速度,那么这里有一个替代库的列表


答案 2

我也遇到了这个问题。以为我会把我的两分钱扔进去,因为这个问题得到了这么多的看法。

设置单元格值

不要单独设置每个单元格的值,而应使用该方法。从维基中获取和修改。fromArray()

$arrayData = array(
array(NULL, 2010, 2011, 2012),
array('Q1',   12,   15,   21),
array('Q2',   56,   73,   86),
array('Q3',   52,   61,   69),
array('Q4',   30,   32,    0),
);

$as = $objPHPExcel->getActiveSheet();

$as->fromArray(
    $arrayData,  // The data to set
    NULL,        // Array values with this value will not be set
    'C3'         // Top left coordinate of the worksheet range where
                 //    we want to set these values (default is A1)
);

样式单元格

静态的

为范围应用样式也比单独设置每个单元格的样式更快(注意模式??)。

$default_style = array(
    'font' => array(
        'name' => 'Verdana',
        'color' => array('rgb' => '000000'),
        'size' => 11
    ),
    'alignment' => array(
        'horizontal' => \PHPExcel_Style_Alignment::HORIZONTAL_CENTER,
        'vertical' => \PHPExcel_Style_Alignment::VERTICAL_CENTER
    ),
    'borders' => array(
        'allborders' => array(
            'style' => \PHPExcel_Style_Border::BORDER_THIN,
            'color' => array('rgb' => 'AAAAAA')
        )
    )
);

// Apply default style to whole sheet
$as->getDefaultStyle()->applyFromArray($default_style);

$titles = array(
    'Name',
    'Number',
    'Address',
    'Telephone'
);

$title_style = array(
    'font' => array(
        'bold' => true
    ),
    'fill' => array(
        'type' => \PHPExcel_Style_Fill::FILL_SOLID,
        'startcolor' => array('rgb' => '5CACEE')
    ),
    'alignment' => array(
        'wrap' => true
    )
);

$as->fromArray($titles, null, 'A1'); // Add titles

$last_col = $as->getHighestColumn(); // Get last column, as a letter

// Apply title style to titles
$as->getStyle('A1:'.$last_col.'1')->applyFromArray($title_style);

动态

我使用PHPExcel将电子表格中给出的数据与数据库中的当前数据进行检查。由于每个单元格都是单独检查的,因此我将样式放在一个数组中(对于无样式为 null),并使用下面的循环来获取要应用样式的单元格范围。

/*
 * $row is previously set in a loop iterating through each 
 *     row from the DB, which is equal to a spreadsheet row.
 * $styles = array(0 => 'error', 1 => 'error', 2 => null, 3 => 'changed', ...);
 */
$start = $end = $style = null;
foreach ($styles as $col => $s) {
    if (!$style && !$s) continue;
    if ($style === $s) {
        $end = $col;
    } else {
        if ($style) {
            $array = null;
            switch ($style) {
                case 'changed':
                    $array = $this->changed_style;
                    break;
                case 'error':
                    $array = $this->error_style;
                    break;
                case 'ignored':
                    $array = $this->ignored_style;
                    break;
            }
            if ($array) { 
                $start = \PHPExcel_Cell::stringFromColumnIndex($start);
                $end = \PHPExcel_Cell::stringFromColumnIndex($end);
                $as->getStyle($start.$row.':'.$end.$row)->applyFromArray($array);
            }
        }
        $start = $end = $col;
        $style = $s;
    }
} 

推荐