Skip to content

Commit 09eacd3

Browse files
committed
Phpstan Bleeding Edge Part 4: Calculation
1 parent c531f5d commit 09eacd3

File tree

17 files changed

+44
-199
lines changed

17 files changed

+44
-199
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,160 +1,5 @@
11
parameters:
22
ignoreErrors:
3-
-
4-
message: "#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#"
5-
count: 2
6-
path: src/PhpSpreadsheet/Calculation/Calculation.php
7-
8-
-
9-
message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#"
10-
count: 1
11-
path: src/PhpSpreadsheet/Calculation/Calculation.php
12-
13-
-
14-
message: "#^Offset 'reference' might not exist on array\\|null\\.$#"
15-
count: 1
16-
path: src/PhpSpreadsheet/Calculation/Calculation.php
17-
18-
-
19-
message: "#^Offset 'type' might not exist on array\\|null\\.$#"
20-
count: 2
21-
path: src/PhpSpreadsheet/Calculation/Calculation.php
22-
23-
-
24-
message: "#^Offset 'value' might not exist on array\\|null\\.$#"
25-
count: 7
26-
path: src/PhpSpreadsheet/Calculation/Calculation.php
27-
28-
-
29-
message: "#^PHPDoc tag @var with type int is not subtype of native type int\\<48, 57\\>\\|int\\<256, 1048576\\>\\|numeric\\-string\\.$#"
30-
count: 1
31-
path: src/PhpSpreadsheet/Calculation/Calculation.php
32-
33-
-
34-
message: "#^Parameter \\#1 \\.\\.\\.\\$arg1 of function max expects non\\-empty\\-array, list\\<\\(int\\|string\\)\\> given\\.$#"
35-
count: 1
36-
path: src/PhpSpreadsheet/Calculation/Calculation.php
37-
38-
-
39-
message: "#^Parameter \\#1 \\.\\.\\.\\$arg1 of function max expects non\\-empty\\-array, list\\<int\\> given\\.$#"
40-
count: 2
41-
path: src/PhpSpreadsheet/Calculation/Calculation.php
42-
43-
-
44-
message: "#^Parameter \\#1 \\.\\.\\.\\$arg1 of function max expects non\\-empty\\-array, list\\<string\\> given\\.$#"
45-
count: 1
46-
path: src/PhpSpreadsheet/Calculation/Calculation.php
47-
48-
-
49-
message: "#^Parameter \\#1 \\.\\.\\.\\$arg1 of function min expects non\\-empty\\-array, list\\<\\(int\\|string\\)\\> given\\.$#"
50-
count: 1
51-
path: src/PhpSpreadsheet/Calculation/Calculation.php
52-
53-
-
54-
message: "#^Parameter \\#1 \\.\\.\\.\\$arg1 of function min expects non\\-empty\\-array, list\\<int\\> given\\.$#"
55-
count: 2
56-
path: src/PhpSpreadsheet/Calculation/Calculation.php
57-
58-
-
59-
message: "#^Parameter \\#1 \\.\\.\\.\\$arg1 of function min expects non\\-empty\\-array, list\\<string\\> given\\.$#"
60-
count: 1
61-
path: src/PhpSpreadsheet/Calculation/Calculation.php
62-
63-
-
64-
message: "#^Offset 0 on non\\-empty\\-list\\<string\\> on left side of \\?\\? always exists and is not nullable\\.$#"
65-
count: 1
66-
path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php
67-
68-
-
69-
message: "#^Parameter &\\$year by\\-ref type of method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Date\\:\\:adjustYearMonth\\(\\) expects int, float given\\.$#"
70-
count: 2
71-
path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Date.php
72-
73-
-
74-
message: "#^Strict comparison using \\!\\=\\= between DateInterval and false will always evaluate to true\\.$#"
75-
count: 1
76-
path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php
77-
78-
-
79-
message: "#^Parameter &\\$testVal3 by\\-ref type of method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:adjustYear\\(\\) expects string, float\\|int given\\.$#"
80-
count: 1
81-
path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php
82-
83-
-
84-
message: "#^Parameter &\\$hour by\\-ref type of method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Time\\:\\:adjustMinute\\(\\) expects int, float given\\.$#"
85-
count: 2
86-
path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php
87-
88-
-
89-
message: "#^Parameter &\\$minute by\\-ref type of method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Time\\:\\:adjustSecond\\(\\) expects int, float given\\.$#"
90-
count: 2
91-
path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php
92-
93-
-
94-
message: "#^Parameter &\\$operand by\\-ref type of method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engine\\\\FormattedNumber\\:\\:convertToNumberIfCurrency\\(\\) expects string, float given\\.$#"
95-
count: 1
96-
path: src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php
97-
98-
-
99-
message: "#^Parameter &\\$operand by\\-ref type of method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engine\\\\FormattedNumber\\:\\:convertToNumberIfNumeric\\(\\) expects string, float given\\.$#"
100-
count: 1
101-
path: src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php
102-
103-
-
104-
message: "#^Parameter &\\$operand by\\-ref type of method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engine\\\\FormattedNumber\\:\\:convertToNumberIfPercent\\(\\) expects string, float given\\.$#"
105-
count: 1
106-
path: src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php
107-
108-
-
109-
message: "#^Strict comparison using \\!\\=\\= between float and null will always evaluate to true\\.$#"
110-
count: 1
111-
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php
112-
113-
-
114-
message: "#^Parameter \\#1 \\.\\.\\.\\$arg1 of function max expects non\\-empty\\-array, array given\\.$#"
115-
count: 1
116-
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php
117-
118-
-
119-
message: "#^Parameter \\#1 \\.\\.\\.\\$arg1 of function min expects non\\-empty\\-array, array given\\.$#"
120-
count: 1
121-
path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php
122-
123-
-
124-
message: "#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#"
125-
count: 1
126-
path: src/PhpSpreadsheet/Calculation/Information/Value.php
127-
128-
-
129-
message: "#^Parameter \\#1 \\$array \\(list\\<mixed\\>\\) of array_values is already a list, call has no effect\\.$#"
130-
count: 1
131-
path: src/PhpSpreadsheet/Calculation/LookupRef/Filter.php
132-
133-
-
134-
message: "#^Offset float does not exist on non\\-empty\\-list\\<mixed\\>\\.$#"
135-
count: 1
136-
path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php
137-
138-
-
139-
message: "#^Call to function is_numeric\\(\\) with float\\|int\\|numeric\\-string will always evaluate to true\\.$#"
140-
count: 1
141-
path: src/PhpSpreadsheet/Calculation/Statistical/Deviations.php
142-
143-
-
144-
message: "#^Call to function is_float\\(\\) with float will always evaluate to true\\.$#"
145-
count: 2
146-
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php
147-
148-
-
149-
message: "#^Offset float does not exist on non\\-empty\\-list\\<mixed\\>\\.$#"
150-
count: 4
151-
path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php
152-
153-
-
154-
message: "#^PHPDoc tag @var with type array is not subtype of native type list\\<mixed\\>\\|false\\.$#"
155-
count: 2
156-
path: src/PhpSpreadsheet/Calculation/TextData/Text.php
157-
1583
-
1594
message: "#^Call to function is_string\\(\\) with numeric\\-string\\|non\\-empty\\-string will always evaluate to true\\.$#"
1605
count: 1

src/PhpSpreadsheet/Calculation/Calculation.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4424,11 +4424,10 @@ private function internalParseFormula(string $formula, ?Cell $cell = null): bool
44244424
if (ctype_digit($val) && $val <= 1048576) {
44254425
// Row range
44264426
$stackItemType = 'Row Reference';
4427-
/** @var int $valx */
44284427
$valx = $val;
44294428
$endRowColRef = ($refSheet !== null) ? $refSheet->getHighestDataColumn($valx) : AddressRange::MAX_COLUMN; // Max 16,384 columns for Excel2007
44304429
$val = "{$rangeWS2}{$endRowColRef}{$val}";
4431-
} elseif (ctype_alpha($val) && is_string($val) && strlen($val) <= 3) {
4430+
} elseif (ctype_alpha($val) && strlen($val) <= 3) {
44324431
// Column range
44334432
$stackItemType = 'Column Reference';
44344433
$endRowColRef = ($refSheet !== null) ? $refSheet->getHighestDataRow($val) : AddressRange::MAX_ROW; // Max 1,048,576 rows for Excel2007
@@ -4562,7 +4561,7 @@ private function internalParseFormula(string $formula, ?Cell $cell = null): bool
45624561

45634562
while (($op = $stack->pop()) !== null) {
45644563
// pop everything off the stack and push onto output
4565-
if ((is_array($op) && $op['value'] == '(')) {
4564+
if ($op['value'] == '(') {
45664565
return $this->raiseFormulaError("Formula Error: Expecting ')'"); // if there are any opening braces on the stack, then braces were unbalanced
45674566
}
45684567
$output[] = $op;
@@ -4819,7 +4818,7 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell
48194818
if ($breakNeeded) {
48204819
break;
48214820
}
4822-
$cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' . Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow);
4821+
$cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' . Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow); // @phpstan-ignore-line
48234822
if ($pCellParent !== null && $this->spreadsheet !== null) {
48244823
$cellValue = $this->extractCellRange($cellRef, $this->spreadsheet->getSheetByName($sheet1), false);
48254824
} else {
@@ -4917,8 +4916,8 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell
49174916
$this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails($cellIntersect));
49184917
$stack->push('Error', ExcelError::null(), null);
49194918
} else {
4920-
$cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':'
4921-
. Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow);
4919+
$cellRef = Coordinate::stringFromColumnIndex(min($oCol) + 1) . min($oRow) . ':' // @phpstan-ignore-line
4920+
. Coordinate::stringFromColumnIndex(max($oCol) + 1) . max($oRow); // @phpstan-ignore-line
49224921
$this->debugLog->writeDebugLog('Evaluation Result is %s', $this->showTypeDetails($cellIntersect));
49234922
$stack->push('Value', $cellIntersect, $cellRef);
49244923
}
@@ -5058,6 +5057,7 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell
50585057
}
50595058

50605059
$functionName = $matches[1];
5060+
/** @var array $argCount */
50615061
$argCount = $stack->pop();
50625062
$argCount = $argCount['value'];
50635063
if ($functionName !== 'MKMATRIX') {
@@ -5088,9 +5088,10 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell
50885088
&& (isset(self::$phpSpreadsheetFunctions[$functionName]['passByReference'][$a]))
50895089
&& (self::$phpSpreadsheetFunctions[$functionName]['passByReference'][$a])
50905090
) {
5091+
/** @var array $arg */
50915092
if ($arg['reference'] === null) {
50925093
$nextArg = $cellID;
5093-
if ($functionName === 'ISREF' && is_array($arg) && ($arg['type'] ?? '') === 'Value') {
5094+
if ($functionName === 'ISREF' && ($arg['type'] ?? '') === 'Value') {
50945095
if (array_key_exists('value', $arg)) {
50955096
$argValue = $arg['value'];
50965097
if (is_scalar($argValue)) {
@@ -5111,6 +5112,7 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell
51115112
}
51125113
}
51135114
} else {
5115+
/** @var array $arg */
51145116
if ($arg['type'] === 'Empty Argument' && in_array($functionName, ['MIN', 'MINA', 'MAX', 'MAXA', 'IF'], true)) {
51155117
$emptyArguments[] = false;
51165118
$args[] = $arg['value'] = 0;
@@ -5233,6 +5235,7 @@ private function processTokenStack(mixed $tokens, ?string $cellID = null, ?Cell
52335235
if ($stack->count() != 1) {
52345236
return $this->raiseFormulaError('internal error');
52355237
}
5238+
/** @var array $output */
52365239
$output = $stack->pop();
52375240
$output = $output['value'];
52385241

@@ -5285,6 +5288,7 @@ private function executeArrayComparison(mixed $operand1, mixed $operand2, string
52855288
foreach ($operand1 as $x => $operandData) {
52865289
$this->debugLog->writeDebugLog('Evaluating Comparison %s %s %s', $this->showValue($operandData), $operation, $this->showValue($operand2));
52875290
$this->executeBinaryComparisonOperation($operandData, $operand2, $operation, $stack);
5291+
/** @var array $r */
52885292
$r = $stack->pop();
52895293
$result[$x] = $r['value'];
52905294
}
@@ -5293,6 +5297,7 @@ private function executeArrayComparison(mixed $operand1, mixed $operand2, string
52935297
foreach ($operand2 as $x => $operandData) {
52945298
$this->debugLog->writeDebugLog('Evaluating Comparison %s %s %s', $this->showValue($operand1), $operation, $this->showValue($operandData));
52955299
$this->executeBinaryComparisonOperation($operand1, $operandData, $operation, $stack);
5300+
/** @var array $r */
52965301
$r = $stack->pop();
52975302
$result[$x] = $r['value'];
52985303
}
@@ -5304,6 +5309,7 @@ private function executeArrayComparison(mixed $operand1, mixed $operand2, string
53045309
foreach ($operand1 as $x => $operandData) {
53055310
$this->debugLog->writeDebugLog('Evaluating Comparison %s %s %s', $this->showValue($operandData), $operation, $this->showValue($operand2[$x]));
53065311
$this->executeBinaryComparisonOperation($operandData, $operand2[$x], $operation, $stack, true);
5312+
/** @var array $r */
53075313
$r = $stack->pop();
53085314
$result[$x] = $r['value'];
53095315
}

src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ private static function buildQuery(array $criteriaNames, array $criteria): strin
108108
}
109109

110110
$rowQuery = array_map(
111-
fn ($rowValue): string => (count($rowValue) > 1) ? 'AND(' . implode(',', $rowValue) . ')' : ($rowValue[0] ?? ''),
111+
fn ($rowValue): string => (count($rowValue) > 1) ? 'AND(' . implode(',', $rowValue) . ')' : ($rowValue[0] ?? ''), // @phpstan-ignore-line
112112
$baseQuery
113113
);
114114

src/PhpSpreadsheet/Calculation/DateTimeExcel/Date.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,11 @@ private static function adjustYearMonth(int &$year, int &$month, int $baseYear):
151151
if ($month < 1) {
152152
// Handle year/month adjustment if month < 1
153153
--$month;
154-
$year += ceil($month / 12) - 1;
154+
$year += (int) (ceil($month / 12) - 1);
155155
$month = 13 - abs($month % 12);
156156
} elseif ($month > 12) {
157157
// Handle year/month adjustment if month > 12
158-
$year += floor($month / 12);
158+
$year += intdiv($month, 12);
159159
$month = ($month % 12);
160160
}
161161

src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public static function between(array|DateTimeInterface|float|int|string $endDate
5050

5151
$days = ExcelError::VALUE();
5252
$diff = $PHPStartDateObject->diff($PHPEndDateObject);
53-
if ($diff !== false && !is_bool($diff->days)) {
53+
if (!is_bool($diff->days)) {
5454
$days = $diff->days;
5555
if ($diff->invert) {
5656
$days = -$days;

src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public static function adjustYear(string $testVal1, string $testVal2, string &$t
119119
if (!is_numeric($testVal1) || $testVal1 < 31) {
120120
if (!is_numeric($testVal2) || $testVal2 < 12) {
121121
if (is_numeric($testVal3) && $testVal3 < 12) {
122-
$testVal3 += 2000;
122+
$testVal3 = (string) ($testVal3 + 2000);
123123
}
124124
}
125125
}

src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,27 +87,27 @@ public static function fromHMS(array|int|float|bool|null|string $hour, array|int
8787
private static function adjustSecond(int &$second, int &$minute): void
8888
{
8989
if ($second < 0) {
90-
$minute += floor($second / 60);
90+
$minute += (int) floor($second / 60);
9191
$second = 60 - abs($second % 60);
9292
if ($second == 60) {
9393
$second = 0;
9494
}
9595
} elseif ($second >= 60) {
96-
$minute += floor($second / 60);
96+
$minute += intdiv($second, 60);
9797
$second = $second % 60;
9898
}
9999
}
100100

101101
private static function adjustMinute(int &$minute, int &$hour): void
102102
{
103103
if ($minute < 0) {
104-
$hour += floor($minute / 60);
104+
$hour += (int) floor($minute / 60);
105105
$minute = 60 - abs($minute % 60);
106106
if ($minute == 60) {
107107
$minute = 0;
108108
}
109109
} elseif ($minute >= 60) {
110-
$hour += floor($minute / 60);
110+
$hour += intdiv($minute, 60);
111111
$minute = $minute % 60;
112112
}
113113
}

src/PhpSpreadsheet/Calculation/Engine/FormattedNumber.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ public static function convertToNumberIfFormatted(string &$operand): bool
4444
* Identify whether a string contains a numeric value,
4545
* and convert it to a numeric if it is.
4646
*
47-
* @param string $operand string value to test
47+
* @param float|string $operand string value to test
4848
*/
49-
public static function convertToNumberIfNumeric(string &$operand): bool
49+
public static function convertToNumberIfNumeric(float|string &$operand): bool
5050
{
5151
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/');
52-
$value = preg_replace(['/(\d)' . $thousandsSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1$2', '$1$2'], trim($operand));
52+
$value = preg_replace(['/(\d)' . $thousandsSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1$2', '$1$2'], trim("$operand"));
5353
$decimalSeparator = preg_quote(StringHelper::getDecimalSeparator(), '/');
5454
$value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? '');
5555

@@ -86,12 +86,12 @@ public static function convertToNumberIfFraction(string &$operand): bool
8686
* Identify whether a string contains a percentage, and if so,
8787
* convert it to a numeric.
8888
*
89-
* @param string $operand string value to test
89+
* @param float|string $operand string value to test
9090
*/
91-
public static function convertToNumberIfPercent(string &$operand): bool
91+
public static function convertToNumberIfPercent(float|string &$operand): bool
9292
{
9393
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/');
94-
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', trim($operand));
94+
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', trim("$operand"));
9595
$decimalSeparator = preg_quote(StringHelper::getDecimalSeparator(), '/');
9696
$value = preg_replace(['/(\d)' . $decimalSeparator . '(\d)/u', '/([+-])\s+(\d)/u'], ['$1.$2', '$1$2'], $value ?? '');
9797

@@ -111,13 +111,13 @@ public static function convertToNumberIfPercent(string &$operand): bool
111111
* Identify whether a string contains a currency value, and if so,
112112
* convert it to a numeric.
113113
*
114-
* @param string $operand string value to test
114+
* @param float|string $operand string value to test
115115
*/
116-
public static function convertToNumberIfCurrency(string &$operand): bool
116+
public static function convertToNumberIfCurrency(float|string &$operand): bool
117117
{
118118
$currencyRegexp = self::currencyMatcherRegexp();
119119
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/');
120-
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $operand);
120+
$value = preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', "$operand");
121121

122122
$match = [];
123123
if ($value !== null && preg_match($currencyRegexp, $value, $match, PREG_UNMATCHED_AS_NULL)) {

0 commit comments

Comments
 (0)