Minor modifications to cyclic reference count logic in calculation engine

This commit is contained in:
MarkBaker 2014-12-05 23:59:41 +00:00
parent 75464688d5
commit 9daca467d6
2 changed files with 23 additions and 28 deletions

View File

@ -58,8 +58,8 @@ class PHPExcel_CalcEngine_CyclicReferenceStack {
* @param mixed $value * @param mixed $value
*/ */
public function push($value) { public function push($value) {
$this->_stack[] = $value; $this->_stack[$value] = $value;
} // function push() }
/** /**
* Pop the last entry from the stack * Pop the last entry from the stack
@ -68,7 +68,7 @@ class PHPExcel_CalcEngine_CyclicReferenceStack {
*/ */
public function pop() { public function pop() {
return array_pop($this->_stack); return array_pop($this->_stack);
} // function pop() }
/** /**
* Test to see if a specified entry exists on the stack * Test to see if a specified entry exists on the stack
@ -76,7 +76,7 @@ class PHPExcel_CalcEngine_CyclicReferenceStack {
* @param mixed $value The value to test * @param mixed $value The value to test
*/ */
public function onStack($value) { public function onStack($value) {
return in_array($value, $this->_stack); return isset($this->_stack[$value]);
} }
/** /**
@ -84,7 +84,7 @@ class PHPExcel_CalcEngine_CyclicReferenceStack {
*/ */
public function clear() { public function clear() {
$this->_stack = array(); $this->_stack = array();
} // function push() }
/** /**
* Return an array of all entries on the stack * Return an array of all entries on the stack
@ -95,4 +95,4 @@ class PHPExcel_CalcEngine_CyclicReferenceStack {
return $this->_stack; return $this->_stack;
} }
} // class PHPExcel_CalcEngine_CyclicReferenceStack }

View File

@ -204,7 +204,7 @@ class PHPExcel_Calculation {
* @var integer * @var integer
* *
*/ */
private $_cyclicFormulaCount = 0; private $_cyclicFormulaCount = 1;
private $_cyclicFormulaCell = ''; private $_cyclicFormulaCell = '';
@ -2236,7 +2236,7 @@ class PHPExcel_Calculation {
$this->formulaError = null; $this->formulaError = null;
$this->_debugLog->clearLog(); $this->_debugLog->clearLog();
$this->_cyclicReferenceStack->clear(); $this->_cyclicReferenceStack->clear();
$this->_cyclicFormulaCount = 0; $this->_cyclicFormulaCount = 1;
self::$returnArrayAsType = self::RETURN_ARRAY_AS_ARRAY; self::$returnArrayAsType = self::RETURN_ARRAY_AS_ARRAY;
} }
@ -2343,24 +2343,22 @@ class PHPExcel_Calculation {
} // function calculateFormula() } // function calculateFormula()
public function getValueFromCache($worksheetName, $cellID, &$cellValue) { public function getValueFromCache($cellReference, &$cellValue) {
// Is calculation cacheing enabled? // Is calculation cacheing enabled?
// Is the value present in calculation cache? // Is the value present in calculation cache?
//echo 'Test cache for ',$worksheetName,'!',$cellID,PHP_EOL; $this->_debugLog->writeDebugLog('Testing cache value for cell ', $cellReference);
$this->_debugLog->writeDebugLog('Testing cache value for cell ', $worksheetName, '!', $cellID); if (($this->_calculationCacheEnabled) && (isset($this->_calculationCache[$cellReference]))) {
if (($this->_calculationCacheEnabled) && (isset($this->_calculationCache[$worksheetName][$cellID]))) { $this->_debugLog->writeDebugLog('Retrieving value for cell ', $cellReference, ' from cache');
//echo 'Retrieve from cache',PHP_EOL;
$this->_debugLog->writeDebugLog('Retrieving value for cell ', $worksheetName, '!', $cellID, ' from cache');
// Return the cached result // Return the cached result
$cellValue = $this->_calculationCache[$worksheetName][$cellID]; $cellValue = $this->_calculationCache[$cellReference];
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
public function saveValueToCache($worksheetName, $cellID, $cellValue) { public function saveValueToCache($cellReference, $cellValue) {
if ($this->_calculationCacheEnabled) { if ($this->_calculationCacheEnabled) {
$this->_calculationCache[$worksheetName][$cellID] = $cellValue; $this->_calculationCache[$cellReference] = $cellValue;
} }
} }
@ -2385,20 +2383,17 @@ class PHPExcel_Calculation {
$pCellParent = ($pCell !== NULL) ? $pCell->getWorksheet() : NULL; $pCellParent = ($pCell !== NULL) ? $pCell->getWorksheet() : NULL;
$wsTitle = ($pCellParent !== NULL) ? $pCellParent->getTitle() : "\x00Wrk"; $wsTitle = ($pCellParent !== NULL) ? $pCellParent->getTitle() : "\x00Wrk";
$wsCellReference = $wsTitle . '!' . $cellID;
if (($cellID !== NULL) && ($this->getValueFromCache($wsTitle, $cellID, $cellValue))) { if (($cellID !== NULL) && ($this->getValueFromCache($wsCellReference, $cellValue))) {
return $cellValue; return $cellValue;
} }
if (($wsTitle{0} !== "\x00") && ($this->_cyclicReferenceStack->onStack($wsTitle.'!'.$cellID))) { if (($wsTitle{0} !== "\x00") && ($this->_cyclicReferenceStack->onStack($wsCellReference))) {
if ($this->cyclicFormulaCount <= 0) { if ($this->cyclicFormulaCount <= 0) {
$this->_cyclicFormulaCell = ''; $this->_cyclicFormulaCell = '';
return $this->_raiseFormulaError('Cyclic Reference in Formula'); return $this->_raiseFormulaError('Cyclic Reference in Formula');
} elseif (($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) && } elseif ($this->_cyclicFormulaCell === $wsCellReference) {
($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID)) {
$this->_cyclicFormulaCell = '';
return $cellValue;
} elseif ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID) {
++$this->_cyclicFormulaCount; ++$this->_cyclicFormulaCount;
if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) { if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) {
$this->_cyclicFormulaCell = ''; $this->_cyclicFormulaCell = '';
@ -2408,18 +2403,18 @@ class PHPExcel_Calculation {
if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) { if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) {
return $cellValue; return $cellValue;
} }
$this->_cyclicFormulaCell = $wsTitle.'!'.$cellID; $this->_cyclicFormulaCell = $wsCellReference;
} }
} }
// Parse the formula onto the token stack and calculate the value // Parse the formula onto the token stack and calculate the value
$this->_cyclicReferenceStack->push($wsTitle.'!'.$cellID); $this->_cyclicReferenceStack->push($wsCellReference);
$cellValue = $this->_processTokenStack($this->_parseFormula($formula, $pCell), $cellID, $pCell); $cellValue = $this->_processTokenStack($this->_parseFormula($formula, $pCell), $cellID, $pCell);
$this->_cyclicReferenceStack->pop(); $this->_cyclicReferenceStack->pop();
// Save to calculation cache // Save to calculation cache
if ($cellID !== NULL) { if ($cellID !== NULL) {
$this->saveValueToCache($wsTitle, $cellID, $cellValue); $this->saveValueToCache($wsCellReference, $cellValue);
} }
// Return the calculated value // Return the calculated value