Skip to content

Commit 35b65be

Browse files
author
Mark Baker
authored
First steps toward array-enabling the information functions (#2608)
* First steps toward array-enabling the information functions Also includes moving unit tests out from Functions and into a separate, dedicated Information folder * Resolve issue with IF(), branch pruning and calculation cache (ensure that we don't convert the if condition to a bool before we've tested to see if it evaluates to an error) More refactoring
1 parent 9893926 commit 35b65be

36 files changed

+817
-341
lines changed

src/PhpSpreadsheet/Calculation/Calculation.php

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PhpOffice\PhpSpreadsheet\Calculation\Engine\CyclicReferenceStack;
66
use PhpOffice\PhpSpreadsheet\Calculation\Engine\Logger;
7+
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
78
use PhpOffice\PhpSpreadsheet\Calculation\Information\Value;
89
use PhpOffice\PhpSpreadsheet\Calculation\Token\Stack;
910
use PhpOffice\PhpSpreadsheet\Cell\Cell;
@@ -1463,12 +1464,12 @@ class Calculation
14631464
],
14641465
'ISERR' => [
14651466
'category' => Category::CATEGORY_INFORMATION,
1466-
'functionCall' => [Information\Value::class, 'isErr'],
1467+
'functionCall' => [Information\ErrorValue::class, 'isErr'],
14671468
'argumentCount' => '1',
14681469
],
14691470
'ISERROR' => [
14701471
'category' => Category::CATEGORY_INFORMATION,
1471-
'functionCall' => [Information\Value::class, 'isError'],
1472+
'functionCall' => [Information\ErrorValue::class, 'isError'],
14721473
'argumentCount' => '1',
14731474
],
14741475
'ISEVEN' => [
@@ -1490,7 +1491,7 @@ class Calculation
14901491
],
14911492
'ISNA' => [
14921493
'category' => Category::CATEGORY_INFORMATION,
1493-
'functionCall' => [Information\Value::class, 'isNa'],
1494+
'functionCall' => [Information\ErrorValue::class, 'isNa'],
14941495
'argumentCount' => '1',
14951496
],
14961497
'ISNONTEXT' => [
@@ -1765,7 +1766,7 @@ class Calculation
17651766
],
17661767
'NA' => [
17671768
'category' => Category::CATEGORY_INFORMATION,
1768-
'functionCall' => [Functions::class, 'NA'],
1769+
'functionCall' => [Information\ExcelError::class, 'NA'],
17691770
'argumentCount' => '0',
17701771
],
17711772
'NEGBINOMDIST' => [
@@ -3894,8 +3895,8 @@ private function internalParseFormula($formula, ?Cell $cell = null)
38943895

38953896
$regexpMatchString = '/^(' . self::CALCULATION_REGEXP_FUNCTION .
38963897
'|' . self::CALCULATION_REGEXP_CELLREF .
3897-
'|' . self::CALCULATION_REGEXP_COLUMN_RANGE .
3898-
'|' . self::CALCULATION_REGEXP_ROW_RANGE .
3898+
'|' . self::CALCULATION_REGEXP_COLUMN_RANGE .
3899+
'|' . self::CALCULATION_REGEXP_ROW_RANGE .
38993900
'|' . self::CALCULATION_REGEXP_NUMBER .
39003901
'|' . self::CALCULATION_REGEXP_STRING .
39013902
'|' . self::CALCULATION_REGEXP_OPENBRACE .
@@ -4009,10 +4010,11 @@ private function internalParseFormula($formula, ?Cell $cell = null)
40094010
--$parenthesisDepthMap[$pendingStoreKey];
40104011
}
40114012

4012-
if (is_array($d) && preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/miu', $d['value'], $matches)) { // Did this parenthesis just close a function?
4013+
if (is_array($d) && preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/miu', $d['value'], $matches)) {
4014+
// Did this parenthesis just close a function?
40134015
if (!empty($pendingStoreKey) && $parenthesisDepthMap[$pendingStoreKey] == -1) {
40144016
// we are closing an IF(
4015-
if ($d['value'] != 'IF(') {
4017+
if ($d['value'] !== 'IF(') {
40164018
return $this->raiseFormulaError('Parser bug we should be in an "IF("');
40174019
}
40184020
if ($expectingConditionMap[$pendingStoreKey]) {
@@ -4427,11 +4429,7 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $cell = null)
44274429

44284430
if (
44294431
isset($storeValue)
4430-
&& (
4431-
!$storeValueAsBool
4432-
|| Value::isError($storeValue)
4433-
|| ($storeValue === 'Pruned branch')
4434-
)
4432+
&& (!$storeValueAsBool || ErrorValue::isError($storeValue) || ($storeValue === 'Pruned branch'))
44354433
) {
44364434
// If branching value is not true, we don't need to compute
44374435
if (!isset($fakedForBranchPruning['onlyIf-' . $onlyIfStoreKey])) {
@@ -4462,11 +4460,7 @@ private function processTokenStack($tokens, $cellID = null, ?Cell $cell = null)
44624460
}
44634461
if (
44644462
isset($storeValue)
4465-
&& (
4466-
$storeValueAsBool
4467-
|| Value::isError($storeValue)
4468-
|| ($storeValue === 'Pruned branch')
4469-
)
4463+
&& ($storeValueAsBool || ErrorValue::isError($storeValue) || ($storeValue === 'Pruned branch'))
44704464
) {
44714465
// If branching value is true, we don't need to compute
44724466
if (!isset($fakedForBranchPruning['onlyIfNot-' . $onlyIfNotStoreKey])) {

src/PhpSpreadsheet/Calculation/Functions.php

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ public static function errorType($value = '')
346346
* @see Information\Value::isBlank()
347347
* Use the isBlank() method in the Information\Value class instead
348348
*
349-
* @return bool
349+
* @return array|bool
350350
*/
351351
public static function isBlank($value = null)
352352
{
@@ -363,11 +363,11 @@ public static function isBlank($value = null)
363363
* @see Information\Value::isErr()
364364
* Use the isErr() method in the Information\Value class instead
365365
*
366-
* @return bool
366+
* @return array|bool
367367
*/
368368
public static function isErr($value = '')
369369
{
370-
return Information\Value::isErr($value);
370+
return Information\ErrorValue::isErr($value);
371371
}
372372

373373
/**
@@ -380,11 +380,11 @@ public static function isErr($value = '')
380380
* @see Information\Value::isError()
381381
* Use the isError() method in the Information\Value class instead
382382
*
383-
* @return bool
383+
* @return array|bool
384384
*/
385385
public static function isError($value = '')
386386
{
387-
return Information\Value::isError($value);
387+
return Information\ErrorValue::isError($value);
388388
}
389389

390390
/**
@@ -397,11 +397,11 @@ public static function isError($value = '')
397397
* @see Information\Value::isNa()
398398
* Use the isNa() method in the Information\Value class instead
399399
*
400-
* @return bool
400+
* @return array|bool
401401
*/
402402
public static function isNa($value = '')
403403
{
404-
return Information\Value::isNa($value);
404+
return Information\ErrorValue::isNa($value);
405405
}
406406

407407
/**
@@ -414,7 +414,7 @@ public static function isNa($value = '')
414414
* @see Information\Value::isEven()
415415
* Use the isEven() method in the Information\Value class instead
416416
*
417-
* @return bool|string
417+
* @return array|bool|string
418418
*/
419419
public static function isEven($value = null)
420420
{
@@ -431,7 +431,7 @@ public static function isEven($value = null)
431431
* @see Information\Value::isOdd()
432432
* Use the isOdd() method in the Information\Value class instead
433433
*
434-
* @return bool|string
434+
* @return array|bool|string
435435
*/
436436
public static function isOdd($value = null)
437437
{
@@ -448,7 +448,7 @@ public static function isOdd($value = null)
448448
* @see Information\Value::isNumber()
449449
* Use the isNumber() method in the Information\Value class instead
450450
*
451-
* @return bool
451+
* @return array|bool
452452
*/
453453
public static function isNumber($value = null)
454454
{
@@ -465,7 +465,7 @@ public static function isNumber($value = null)
465465
* @see Information\Value::isLogical()
466466
* Use the isLogical() method in the Information\Value class instead
467467
*
468-
* @return bool
468+
* @return array|bool
469469
*/
470470
public static function isLogical($value = null)
471471
{
@@ -482,7 +482,7 @@ public static function isLogical($value = null)
482482
* @see Information\Value::isText()
483483
* Use the isText() method in the Information\Value class instead
484484
*
485-
* @return bool
485+
* @return array|bool
486486
*/
487487
public static function isText($value = null)
488488
{
@@ -499,7 +499,7 @@ public static function isText($value = null)
499499
* @see Information\Value::isNonText()
500500
* Use the isNonText() method in the Information\Value class instead
501501
*
502-
* @return bool
502+
* @return array|bool
503503
*/
504504
public static function isNonText($value = null)
505505
{
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet\Calculation\Information;
4+
5+
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
6+
7+
class ErrorValue
8+
{
9+
use ArrayEnabled;
10+
11+
/**
12+
* IS_ERR.
13+
*
14+
* @param mixed $value Value to check
15+
* Or can be an array of values
16+
*
17+
* @return array|bool
18+
* If an array of numbers is passed as an argument, then the returned result will also be an array
19+
* with the same dimensions
20+
*/
21+
public static function isErr($value = '')
22+
{
23+
if (is_array($value)) {
24+
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
25+
}
26+
27+
return self::isError($value) && (!self::isNa(($value)));
28+
}
29+
30+
/**
31+
* IS_ERROR.
32+
*
33+
* @param mixed $value Value to check
34+
* Or can be an array of values
35+
*
36+
* @return array|bool
37+
* If an array of numbers is passed as an argument, then the returned result will also be an array
38+
* with the same dimensions
39+
*/
40+
public static function isError($value = '')
41+
{
42+
if (is_array($value)) {
43+
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
44+
}
45+
46+
if (!is_string($value)) {
47+
return false;
48+
}
49+
50+
return in_array($value, ExcelError::$errorCodes);
51+
}
52+
53+
/**
54+
* IS_NA.
55+
*
56+
* @param mixed $value Value to check
57+
* Or can be an array of values
58+
*
59+
* @return array|bool
60+
* If an array of numbers is passed as an argument, then the returned result will also be an array
61+
* with the same dimensions
62+
*/
63+
public static function isNa($value = '')
64+
{
65+
if (is_array($value)) {
66+
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
67+
}
68+
69+
return $value === ExcelError::NA();
70+
}
71+
}

0 commit comments

Comments
 (0)