diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index fcfebba6a4..5674cb72ad 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -3345,18 +3345,15 @@ public function calculateFormula($formula, $cellID = null, ?Cell $pCell = null) } /** - * @param string $cellReference * @param mixed $cellValue - * - * @return bool */ - public function getValueFromCache($cellReference, &$cellValue) + public function getValueFromCache(string $cellReference, &$cellValue): bool { + $this->debugLog->writeDebugLog("Testing cache value for cell {$cellReference}"); // Is calculation cacheing enabled? - // Is the value present in calculation cache? - $this->debugLog->writeDebugLog('Testing cache value for cell ', $cellReference); + // If so, is the required value present in calculation cache? if (($this->calculationCacheEnabled) && (isset($this->calculationCache[$cellReference]))) { - $this->debugLog->writeDebugLog('Retrieving value for cell ', $cellReference, ' from cache'); + $this->debugLog->writeDebugLog("Retrieving value for cell {$cellReference} from cache"); // Return the cached result $cellValue = $this->calculationCache[$cellReference]; @@ -3418,7 +3415,7 @@ public function _calculateFormulaValue($formula, $cellID = null, ?Cell $pCell = if (($cellID !== null) && ($this->getValueFromCache($wsCellReference, $cellValue))) { return $cellValue; } - $this->debugLog->writeDebugLog('Evaluating formula for cell ', $wsCellReference); + $this->debugLog->writeDebugLog("Evaluating formula for cell {$wsCellReference}"); if (($wsTitle[0] !== "\x00") && ($this->cyclicReferenceStack->onStack($wsCellReference))) { if ($this->cyclicFormulaCount <= 0) { @@ -3440,7 +3437,7 @@ public function _calculateFormulaValue($formula, $cellID = null, ?Cell $pCell = } } - $this->debugLog->writeDebugLog('Formula for cell ', $wsCellReference, ' is ', $formula); + $this->debugLog->writeDebugLog("Formula for cell {$wsCellReference} is {$formula}"); // Parse the formula onto the token stack and calculate the value $this->cyclicReferenceStack->push($wsCellReference); @@ -4805,6 +4802,53 @@ private function validateBinaryOperand(&$operand, &$stack) return true; } + /** + * @param null|string $cellID + * @param mixed $operand1 + * @param mixed $operand2 + * @param string $operation + * + * @return array + */ + private function executeArrayComparison($cellID, $operand1, $operand2, $operation, Stack &$stack, bool $recursingArrays) + { + $result = []; + if (!is_array($operand2)) { + // Operand 1 is an array, Operand 2 is a scalar + foreach ($operand1 as $x => $operandData) { + $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2)); + $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2, $operation, $stack); + $r = $stack->pop(); + $result[$x] = $r['value']; + } + } elseif (!is_array($operand1)) { + // Operand 1 is a scalar, Operand 2 is an array + foreach ($operand2 as $x => $operandData) { + $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operand1), ' ', $operation, ' ', $this->showValue($operandData)); + $this->executeBinaryComparisonOperation($cellID, $operand1, $operandData, $operation, $stack); + $r = $stack->pop(); + $result[$x] = $r['value']; + } + } else { + // Operand 1 and Operand 2 are both arrays + if (!$recursingArrays) { + self::checkMatrixOperands($operand1, $operand2, 2); + } + foreach ($operand1 as $x => $operandData) { + $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2[$x])); + $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2[$x], $operation, $stack, true); + $r = $stack->pop(); + $result[$x] = $r['value']; + } + } + // Log the result details + $this->debugLog->writeDebugLog('Comparison Evaluation Result is ', $this->showTypeDetails($result)); + // And push the result onto the stack + $stack->push('Array', $result); + + return $result; + } + /** * @param null|string $cellID * @param mixed $operand1 @@ -4818,38 +4862,7 @@ private function executeBinaryComparisonOperation($cellID, $operand1, $operand2, { // If we're dealing with matrix operations, we want a matrix result if ((is_array($operand1)) || (is_array($operand2))) { - $result = []; - if ((is_array($operand1)) && (!is_array($operand2))) { - foreach ($operand1 as $x => $operandData) { - $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2)); - $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2, $operation, $stack); - $r = $stack->pop(); - $result[$x] = $r['value']; - } - } elseif ((!is_array($operand1)) && (is_array($operand2))) { - foreach ($operand2 as $x => $operandData) { - $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operand1), ' ', $operation, ' ', $this->showValue($operandData)); - $this->executeBinaryComparisonOperation($cellID, $operand1, $operandData, $operation, $stack); - $r = $stack->pop(); - $result[$x] = $r['value']; - } - } else { - if (!$recursingArrays) { - self::checkMatrixOperands($operand1, $operand2, 2); - } - foreach ($operand1 as $x => $operandData) { - $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2[$x])); - $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2[$x], $operation, $stack, true); - $r = $stack->pop(); - $result[$x] = $r['value']; - } - } - // Log the result details - $this->debugLog->writeDebugLog('Comparison Evaluation Result is ', $this->showTypeDetails($result)); - // And push the result onto the stack - $stack->push('Array', $result); - - return $result; + return $this->executeArrayComparison($cellID, $operand1, $operand2, $operation, $stack, $recursingArrays); } // Simple validate the two operands if they are string values @@ -4863,10 +4876,10 @@ private function executeBinaryComparisonOperation($cellID, $operand1, $operand2, // Use case insensitive comparaison if not OpenOffice mode if (Functions::getCompatibilityMode() != Functions::COMPATIBILITY_OPENOFFICE) { if (is_string($operand1)) { - $operand1 = strtoupper($operand1); + $operand1 = Shared\StringHelper::strToUpper($operand1); } if (is_string($operand2)) { - $operand2 = strtoupper($operand2); + $operand2 = Shared\StringHelper::strToUpper($operand2); } } diff --git a/src/PhpSpreadsheet/Calculation/Logical/Conditional.php b/src/PhpSpreadsheet/Calculation/Logical/Conditional.php index 12256d3409..e84d0f33e4 100644 --- a/src/PhpSpreadsheet/Calculation/Logical/Conditional.php +++ b/src/PhpSpreadsheet/Calculation/Logical/Conditional.php @@ -83,11 +83,11 @@ public static function statementSwitch(...$arguments) $targetValue = Functions::flattenSingleValue($arguments[0]); $argc = count($arguments) - 1; $switchCount = floor($argc / 2); - $switchSatisfied = false; $hasDefaultClause = $argc % 2 !== 0; - $defaultClause = $argc % 2 === 0 ? null : $arguments[count($arguments) - 1]; + $defaultClause = $argc % 2 === 0 ? null : $arguments[$argc]; - if ($switchCount) { + $switchSatisfied = false; + if ($switchCount > 0) { for ($index = 0; $index < $switchCount; ++$index) { if ($targetValue == $arguments[$index * 2 + 1]) { $result = $arguments[$index * 2 + 2]; @@ -98,7 +98,7 @@ public static function statementSwitch(...$arguments) } } - if (!$switchSatisfied) { + if ($switchSatisfied !== true) { $result = $hasDefaultClause ? $defaultClause : Functions::NA(); } } @@ -161,12 +161,14 @@ public static function IFNA($testValue = '', $napart = '') */ public static function IFS(...$arguments) { - if (count($arguments) % 2 != 0) { + $argumentCount = count($arguments); + + if ($argumentCount % 2 != 0) { return Functions::NA(); } // We use instance of Exception as a falseValue in order to prevent string collision with value in cell $falseValueException = new Exception(); - for ($i = 0; $i < count($arguments); $i += 2) { + for ($i = 0; $i < $argumentCount; $i += 2) { $testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]); $returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]); $result = self::statementIf($testValue, $returnIfTrue, $falseValueException); diff --git a/src/PhpSpreadsheet/Cell/Coordinate.php b/src/PhpSpreadsheet/Cell/Coordinate.php index 2afeebe9dd..8d81f3a1ca 100644 --- a/src/PhpSpreadsheet/Cell/Coordinate.php +++ b/src/PhpSpreadsheet/Cell/Coordinate.php @@ -339,7 +339,8 @@ public static function extractAllCellReferencesInRange($cellRange): array private static function processRangeSetOperators(array $operators, array $cells): array { - for ($offset = 0; $offset < count($operators); ++$offset) { + $operatorCount = count($operators); + for ($offset = 0; $offset < $operatorCount; ++$offset) { $operator = $operators[$offset]; if ($operator !== ' ') { continue; @@ -350,6 +351,7 @@ private static function processRangeSetOperators(array $operators, array $cells) $operators = array_values($operators); $cells = array_values($cells); --$offset; + --$operatorCount; } return $cells; diff --git a/src/PhpSpreadsheet/Document/Properties.php b/src/PhpSpreadsheet/Document/Properties.php index 0876a9ed48..d6aff81ebe 100644 --- a/src/PhpSpreadsheet/Document/Properties.php +++ b/src/PhpSpreadsheet/Document/Properties.php @@ -506,49 +506,33 @@ public static function convertProperty($propertyValue, $propertyType) switch ($propertyType) { case 'empty': // Empty return ''; - - break; case 'null': // Null return null; - - break; case 'i1': // 1-Byte Signed Integer case 'i2': // 2-Byte Signed Integer case 'i4': // 4-Byte Signed Integer case 'i8': // 8-Byte Signed Integer case 'int': // Integer return (int) $propertyValue; - - break; case 'ui1': // 1-Byte Unsigned Integer case 'ui2': // 2-Byte Unsigned Integer case 'ui4': // 4-Byte Unsigned Integer case 'ui8': // 8-Byte Unsigned Integer case 'uint': // Unsigned Integer return abs((int) $propertyValue); - - break; case 'r4': // 4-Byte Real Number case 'r8': // 8-Byte Real Number case 'decimal': // Decimal return (float) $propertyValue; - - break; case 'lpstr': // LPSTR case 'lpwstr': // LPWSTR case 'bstr': // Basic String return $propertyValue; - - break; case 'date': // Date and Time case 'filetime': // File Time return strtotime($propertyValue); - - break; case 'bool': // Boolean return $propertyValue == 'true'; - - break; case 'cy': // Currency case 'error': // Error Status Code case 'vector': // Vector @@ -563,8 +547,6 @@ public static function convertProperty($propertyValue, $propertyType) case 'clsid': // Class ID case 'cf': // Clipboard Data return $propertyValue; - - break; } return $propertyValue; @@ -584,31 +566,21 @@ public static function convertPropertyType($propertyType) case 'ui8': // 8-Byte Unsigned Integer case 'uint': // Unsigned Integer return self::PROPERTY_TYPE_INTEGER; - - break; case 'r4': // 4-Byte Real Number case 'r8': // 8-Byte Real Number case 'decimal': // Decimal return self::PROPERTY_TYPE_FLOAT; - - break; case 'empty': // Empty case 'null': // Null case 'lpstr': // LPSTR case 'lpwstr': // LPWSTR case 'bstr': // Basic String return self::PROPERTY_TYPE_STRING; - - break; case 'date': // Date and Time case 'filetime': // File Time return self::PROPERTY_TYPE_DATE; - - break; case 'bool': // Boolean return self::PROPERTY_TYPE_BOOLEAN; - - break; case 'cy': // Currency case 'error': // Error Status Code case 'vector': // Vector @@ -623,8 +595,6 @@ public static function convertPropertyType($propertyType) case 'clsid': // Class ID case 'cf': // Clipboard Data return self::PROPERTY_TYPE_UNKNOWN; - - break; } return self::PROPERTY_TYPE_UNKNOWN;