如何提高PHPExcel的公式计算?

我是PHPExcel的新手,我已经search了谷歌,但没有find我的具体问题在这里。 我发现更新/评估表单中的公式非常慢。

我有一个非常小的excel文件,我正在做一些非常基本的目标寻求(在PHP中完成目标,在Excel表中完成最终结果计算)。 我已经准确地工作了,但速度绝对会令我失望。 看来公式计算是怪罪 – 公式计算/更新如何加速?

不幸的是,由于内容是我公司的商业秘密,我不能发布excel文件的副本,但这并不是什么不寻常的事情。 公式中非常简单的算术。 我能想到的唯一可能会有一个效果是,一些细胞依赖链可能有点长(15-ish依赖)。

正如你从下面的输出中可以看到的那样,我们只执行11次迭代来寻找目标,总共花费4-5秒。 由于这将是一个AJAX服务,我真的需要它比这更快。

这是非常快速和肮脏的概念validation码,请耐心等待:

<?php Stopwatch::start(); $inputFileType = PHPExcel_IOFactory::identify( './example.xlsx' ); var_dump( 'FileType: '.$inputFileType ); Stopwatch::rel( 'identify filetype' ); $objReader = PHPExcel_IOFactory::createReader( $inputFileType ); $objReader->setReadDataOnly( true ); $filterSubset = new ReadFilter( 1, 35, range( 'A', 'J' )); $objReader->setReadFilter( $filterSubset ); Stopwatch::rel( 'create reader' ); $objPHPExcel = $objReader->load( $inputFileName ); Stopwatch::rel( 'load file' ); $data = $objPHPExcel->getSheetByName( 'Data' ); $inputCell = $data->getCell( 'B9' ); $outputCell = $data->getCell( 'B35' ); Stopwatch::rel( 'get cells' ); goalSeek( $inputCell, $outputCell, '0.10', 1, 5 ); function goalSeek( $inputCell, $outputCell, $targetValue ) { $cellValue = function() use ( &$outputCell, $precision ) { return round( $outputCell->getCalculatedValue(), $precision ); }; $setValue = function( $value ) use ( &$inputCell, &$objPHPExcel, $cellValue ) { $inputCell->setValue( $value ); PHPExcel_Calculation::getInstance( $objPHPExcel )->clearCalculationCache(); // -- clear cache so updates are calculated Stopwatch::rel( 'goal-seek' ); }; // -- very basic goal seeking psuedo-code while( $stillHunting ) { // -- outside tolerance $setValue( $newInputValue ); } }; class ReadFilter implements PHPExcel_Reader_IReadFilter { private $_startRow = 0; private $_endRow = 0; private $_columns = []; public function __construct( $startRow, $endRow, $columns ) { $this->_startRow = $startRow; $this->_endRow = $endRow; $this->_columns = $columns; } public function readCell( $column, $row, $worksheetName = '' ) { if( $row >= $this->_startRow && $row <= $this->_endRow ) { // -- valid row if( in_array( $column, $this->_columns )) { // -- valid column return true; } } // else (implicit) return false; } } 

产量

 string 'FileType: Excel2007' (length=19) array (size=2) 'rel' => array (size=17) 'identify' => float 0.008597135543823242 'create reader' => float 0.0001199245452880859 'load file' => float 0.387645959854126 'get cells' => float 5.292892456054688E-5 'goal-seek' => float 0.4194750785827637 'goal-seek2' => float 0.3829901218414307 'goal-seek3' => float 0.3478608131408691 'goal-seek4' => float 0.3471150398254395 'goal-seek5' => float 0.3569440841674805 'goal-seek6' => float 0.378180980682373 'goal-seek7' => float 0.3683559894561768 'goal-seek8' => float 0.3778479099273682 'goal-seek9' => float 0.3664979934692383 'goal-seek10' => float 0.4503841400146484 '_avg' => float 0.2794940630594889 '_untilStop' => float 0.5339441299438477 'total' => float 4.726345062255859 

好的,如果你正在重新计算相同的公式,可能会加快速度的一个可能的解决scheme,但是在相关的单元格中有不同的值就是parsing公式一次,只有一次,但是执行多次。

getCalculatedValue()调用两个方法; 第一个是parseFormula() ,它接受公式作为一个string,并为该公式的执行构build一个parsing器堆栈(作为一个数组)。 第二个方法(私有方法,所以你需要在Calculation.php中将其改为public)是processTokenStack() ,它接受3个参数,由parseFormula()调用产生的令牌栈,单元格ID(作为一个string)和单元格对象。

您可能只执行一次parseFormula()步骤,然后为每个迭代调用processTokenStack() ,这将消除除第一次迭代之外的所有parsing步骤