Skip to content

Commit 0e22939

Browse files
author
MarkBaker
committed
Ensure full support for vector/matrix combinations and for asymetric matrix/matrix arguments
Re-baseline phpstan
1 parent db502ce commit 0e22939

File tree

5 files changed

+225
-87
lines changed

5 files changed

+225
-87
lines changed

phpstan-baseline.neon

+48-43
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,13 @@ parameters:
6666
path: src/PhpSpreadsheet/Calculation/Calculation.php
6767

6868
-
69-
message: "#^Cannot access offset int(<0, max>)? on mixed\\.$#"
70-
count: 16
69+
message: "#^Cannot access offset int on mixed\\.$#"
70+
count: 10
71+
path: src/PhpSpreadsheet/Calculation/Calculation.php
72+
73+
-
74+
message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#"
75+
count: 6
7176
path: src/PhpSpreadsheet/Calculation/Calculation.php
7277

7378
-
@@ -1461,7 +1466,7 @@ parameters:
14611466
path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php
14621467

14631468
-
1464-
message: "#^Parameter \\#1 \\$array_arg of function uasort expects array(<T>)?, mixed given\\.$#"
1469+
message: "#^Parameter \\#1 \\$array_arg of function uasort expects array\\<T\\>, mixed given\\.$#"
14651470
count: 1
14661471
path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php
14671472

@@ -1471,54 +1476,34 @@ parameters:
14711476
path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php
14721477

14731478
-
1474-
message: "#^Parameter \\#2 \\$callback of function uasort expects callable\\((mixed|T), (mixed|T)\\)\\: int, array\\{'self', 'vlookupSort'\\} given\\.$#"
1479+
message: "#^Parameter \\#2 \\$callback of function uasort expects callable\\(T, T\\)\\: int, array\\{'self', 'vlookupSort'\\} given\\.$#"
14751480
count: 1
14761481
path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php
14771482

14781483
-
1479-
message: "#^Parameter \\#1 \\$number of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Trig\\\\Cosine\\:\\:acos\\(\\) expects float, mixed given\\.$#"
1480-
count: 1
1481-
path: src/PhpSpreadsheet/Calculation/MathTrig.php
1482-
1483-
-
1484-
message: "#^Parameter \\#1 \\$number of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Trig\\\\Cosine\\:\\:acosh\\(\\) expects float, mixed given\\.$#"
1485-
count: 1
1486-
path: src/PhpSpreadsheet/Calculation/MathTrig.php
1487-
1488-
-
1489-
message: "#^Parameter \\#1 \\$number of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Trig\\\\Sine\\:\\:asin\\(\\) expects float, mixed given\\.$#"
1490-
count: 1
1491-
path: src/PhpSpreadsheet/Calculation/MathTrig.php
1492-
1493-
-
1494-
message: "#^Parameter \\#1 \\$number of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Trig\\\\Sine\\:\\:asinh\\(\\) expects float, mixed given\\.$#"
1484+
message: "#^Cannot cast mixed to string\\.$#"
14951485
count: 1
1496-
path: src/PhpSpreadsheet/Calculation/MathTrig.php
1486+
path: src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php
14971487

14981488
-
1499-
message: "#^Parameter \\#1 \\$number of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Trig\\\\Tangent\\:\\:atan\\(\\) expects float, mixed given\\.$#"
1500-
count: 1
1501-
path: src/PhpSpreadsheet/Calculation/MathTrig.php
1489+
message: "#^Binary operation \"/\" between array\\|float\\|int\\|string and array\\|float\\|int\\|string results in an error\\.$#"
1490+
count: 2
1491+
path: src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php
15021492

15031493
-
1504-
message: "#^Parameter \\#1 \\$number of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Trig\\\\Tangent\\:\\:atanh\\(\\) expects float, mixed given\\.$#"
1494+
message: "#^Parameter \\#1 \\$factVal of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Factorial\\:\\:fact\\(\\) expects array\\|float, int\\<min, \\-2\\>\\|int\\<0, max\\> given\\.$#"
15051495
count: 1
1506-
path: src/PhpSpreadsheet/Calculation/MathTrig.php
1496+
path: src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php
15071497

15081498
-
1509-
message: "#^Cannot cast mixed to string\\.$#"
1499+
message: "#^Binary operation \"/\" between array\\|float\\|int\\|string and float\\|int results in an error\\.$#"
15101500
count: 1
1511-
path: src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php
1512-
1513-
-
1514-
message: "#^Binary operation \"/\" between float\\|int\\|string and float\\|int\\|string results in an error\\.$#"
1515-
count: 2
1516-
path: src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php
1501+
path: src/PhpSpreadsheet/Calculation/MathTrig/Factorial.php
15171502

15181503
-
1519-
message: "#^Binary operation \"/\" between float\\|int\\|string and float\\|int results in an error\\.$#"
1504+
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\IntClass\\:\\:evaluate\\(\\) should return array\\|string but returns int\\.$#"
15201505
count: 1
1521-
path: src/PhpSpreadsheet/Calculation/MathTrig/Factorial.php
1506+
path: src/PhpSpreadsheet/Calculation/MathTrig/IntClass.php
15221507

15231508
-
15241509
message: "#^Cannot call method getWorksheet\\(\\) on mixed\\.$#"
@@ -1810,6 +1795,11 @@ parameters:
18101795
count: 1
18111796
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php
18121797

1798+
-
1799+
message: "#^Parameter \\#1 \\$factVal of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Factorial\\:\\:fact\\(\\) expects array\\|float, int\\<0, max\\> given\\.$#"
1800+
count: 1
1801+
path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php
1802+
18131803
-
18141804
message: "#^Binary operation \"\\-\" between float\\|string and float\\|int\\|numeric\\-string results in an error\\.$#"
18151805
count: 1
@@ -1841,7 +1831,7 @@ parameters:
18411831
path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php
18421832

18431833
-
1844-
message: "#^Binary operation \"/\" between float\\|int\\|string and float\\|int\\|string results in an error\\.$#"
1834+
message: "#^Binary operation \"/\" between array\\|float\\|int\\|string and array\\|float\\|int\\|string results in an error\\.$#"
18451835
count: 1
18461836
path: src/PhpSpreadsheet/Calculation/Statistical/Permutations.php
18471837

@@ -6046,8 +6036,13 @@ parameters:
60466036
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
60476037

60486038
-
6049-
message: "#^Parameter \\#1 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:removeRow\\(\\) expects string, int(<1, max>)? given\\.$#"
6050-
count: 2
6039+
message: "#^Parameter \\#1 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:removeRow\\(\\) expects string, int given\\.$#"
6040+
count: 1
6041+
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
6042+
6043+
-
6044+
message: "#^Parameter \\#1 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:removeRow\\(\\) expects string, int\\<1, max\\> given\\.$#"
6045+
count: 1
60516046
path: src/PhpSpreadsheet/Worksheet/Worksheet.php
60526047

60536048
-
@@ -6996,7 +6991,7 @@ parameters:
69966991
path: src/PhpSpreadsheet/Writer/Xlsx.php
69976992

69986993
-
6999-
message: "#^Cannot access offset int(<0, max>)? on mixed\\.$#"
6994+
message: "#^Cannot access offset int\\<0, max\\> on mixed\\.$#"
70006995
count: 2
70016996
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
70026997

@@ -7161,7 +7156,7 @@ parameters:
71617156
path: src/PhpSpreadsheet/Writer/Xlsx/DocProps.php
71627157

71637158
-
7164-
message: "#^Parameter \\#1 \\$index of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getChartByIndex\\(\\) expects string, int(<0, max>)? given\\.$#"
7159+
message: "#^Parameter \\#1 \\$index of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getChartByIndex\\(\\) expects string, int\\<0, max\\> given\\.$#"
71657160
count: 1
71667161
path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php
71677162

@@ -7401,7 +7396,7 @@ parameters:
74017396
path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
74027397

74037398
-
7404-
message: "#^Offset int(<1, max>)? on array\\<string, non\\-empty\\-array\\<int, string\\>\\> in isset\\(\\) does not exist\\.$#"
7399+
message: "#^Offset int\\<1, max\\> on array\\<string, non\\-empty\\-array\\<int, string\\>\\> in isset\\(\\) does not exist\\.$#"
74057400
count: 2
74067401
path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
74077402

@@ -7436,8 +7431,18 @@ parameters:
74367431
path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
74377432

74387433
-
7439-
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, (int|int\\<(0|1), max\\>) given\\.$#"
7440-
count: 27
7434+
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#"
7435+
count: 15
7436+
path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
7437+
7438+
-
7439+
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<0, max\\> given\\.$#"
7440+
count: 3
7441+
path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
7442+
7443+
-
7444+
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<1, max\\> given\\.$#"
7445+
count: 9
74417446
path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
74427447

74437448
-

src/PhpSpreadsheet/Calculation/ArrayEnabled.php

+63-35
Original file line numberDiff line numberDiff line change
@@ -54,63 +54,91 @@ protected static function evaluateArrayArguments(callable $method, ...$arguments
5454
return self::evaluateVectorPair($method, $singleRowVectorIndex, $singleColumnVectorIndex, ...$arguments);
5555
}
5656

57-
$rowVectorIndexes = self::$arrayArgumentHelper->getRowVectors();
58-
$columnVectorIndexes = self::$arrayArgumentHelper->getColumnVectors();
59-
60-
// Logic for a two row vectors or two column vectors
61-
if (count($rowVectorIndexes) === 2 && count($columnVectorIndexes) === 0) {
62-
return self::evaluateRowVectorPair($method, $rowVectorIndexes, ...$arguments);
63-
} elseif (count($rowVectorIndexes) === 0 && count($columnVectorIndexes) === 2) {
64-
return self::evaluateColumnVectorPair($method, $columnVectorIndexes, ...$arguments);
57+
$matrixPair = self::$arrayArgumentHelper->getMatrixPair();
58+
if ($matrixPair !== []) {
59+
if (
60+
(self::$arrayArgumentHelper->isVector($matrixPair[0]) === true &&
61+
self::$arrayArgumentHelper->isVector($matrixPair[1]) === false) ||
62+
(self::$arrayArgumentHelper->isVector($matrixPair[0]) === false &&
63+
self::$arrayArgumentHelper->isVector($matrixPair[1]) === true)
64+
) {
65+
// Logic for a matrix and a vector (row or column)
66+
return self::evaluateVectorMatrixPair($method, $matrixPair, ...$arguments);
67+
}
68+
// Logic for matrix/matrix, column vector/column vector or row vector/row vector
69+
return self::evaluateMatrixPair($method, $matrixPair, ...$arguments);
6570
}
6671

67-
// If we have multiple arrays, and they don't match a row vector/column vector pattern,
68-
// or two row vectors and two column vectors,
69-
// then we drop through to an error return for the moment
70-
// Still need to work out the logic for multiple matrices as array arguments,
71-
// or when we have more than two arrays
72+
// Still need to work out the logic for more than two array arguments,
7273
return ['#VALUE!'];
7374
}
7475

7576
/**
7677
* @param mixed ...$arguments
7778
*/
78-
private static function evaluateRowVectorPair(callable $method, array $vectorIndexes, ...$arguments): array
79+
private static function evaluateVectorMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array
7980
{
80-
$vector2 = array_pop($vectorIndexes);
81-
$vectorValues2 = Functions::flattenArray($arguments[$vector2]);
82-
$vector1 = array_pop($vectorIndexes);
83-
$vectorValues1 = Functions::flattenArray($arguments[$vector1]);
81+
$matrix2 = array_pop($matrixIndexes);
82+
/** @var array $matrixValues2 */
83+
$matrixValues2 = $arguments[$matrix2];
84+
$matrix1 = array_pop($matrixIndexes);
85+
/** @var array $matrixValues1 */
86+
$matrixValues1 = $arguments[$matrix1];
87+
88+
$rows = min(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
89+
$columns = min(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
90+
91+
if ($rows === 1) {
92+
$rows = max(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
93+
}
94+
if ($columns === 1) {
95+
$columns = max(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
96+
}
8497

8598
$result = [];
86-
foreach ($vectorValues1 as $index => $value1) {
87-
$value2 = $vectorValues2[$index];
88-
$arguments[$vector1] = $value1;
89-
$arguments[$vector2] = $value2;
90-
91-
$result[] = $method(...$arguments);
99+
for ($rowIndex = 0; $rowIndex < $rows; ++$rowIndex) {
100+
for ($columnIndex = 0; $columnIndex < $columns; ++$columnIndex) {
101+
$rowIndex1 = self::$arrayArgumentHelper->isRowVector($matrix1) ? 0 : $rowIndex;
102+
$columnIndex1 = self::$arrayArgumentHelper->isColumnVector($matrix1) ? 0 : $columnIndex;
103+
$value1 = $matrixValues1[$rowIndex1][$columnIndex1];
104+
$rowIndex2 = self::$arrayArgumentHelper->isRowVector($matrix2) ? 0 : $rowIndex;
105+
$columnIndex2 = self::$arrayArgumentHelper->isColumnVector($matrix2) ? 0 : $columnIndex;
106+
$value2 = $matrixValues2[$rowIndex2][$columnIndex2];
107+
$arguments[$matrix1] = $value1;
108+
$arguments[$matrix2] = $value2;
109+
110+
$result[$rowIndex][$columnIndex] = $method(...$arguments);
111+
}
92112
}
93113

94-
return [$result];
114+
return $result;
95115
}
96116

97117
/**
98118
* @param mixed ...$arguments
99119
*/
100-
private static function evaluateColumnVectorPair(callable $method, array $vectorIndexes, ...$arguments): array
120+
private static function evaluateMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array
101121
{
102-
$vector2 = array_pop($vectorIndexes);
103-
$vectorValues2 = Functions::flattenArray($arguments[$vector2]);
104-
$vector1 = array_pop($vectorIndexes);
105-
$vectorValues1 = Functions::flattenArray($arguments[$vector1]);
122+
$matrix2 = array_pop($matrixIndexes);
123+
/** @var array $matrixValues2 */
124+
$matrixValues2 = $arguments[$matrix2];
125+
$matrix1 = array_pop($matrixIndexes);
126+
/** @var array $matrixValues1 */
127+
$matrixValues1 = $arguments[$matrix1];
106128

107129
$result = [];
108-
foreach ($vectorValues1 as $index => $value1) {
109-
$value2 = $vectorValues2[$index];
110-
$arguments[$vector1] = $value1;
111-
$arguments[$vector2] = $value2;
130+
foreach ($matrixValues1 as $rowIndex => $row) {
131+
foreach ($row as $columnIndex => $value1) {
132+
if (isset($matrixValues2[$rowIndex][$columnIndex]) === false) {
133+
continue;
134+
}
112135

113-
$result[] = [$method(...$arguments)];
136+
$value2 = $matrixValues2[$rowIndex][$columnIndex];
137+
$arguments[$matrix1] = $value1;
138+
$arguments[$matrix2] = $value2;
139+
140+
$result[$rowIndex][$columnIndex] = $method(...$arguments);
141+
}
114142
}
115143

116144
return $result;

src/PhpSpreadsheet/Calculation/Engine/ArrayArgumentHelper.php

+46-8
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,14 @@ public function getFirstArrayArgumentNumber(): int
7575
return 0;
7676
}
7777

78-
public function getRowVectors(): array
78+
public function getSingleRowVector(): ?int
79+
{
80+
$rowVectors = $this->getRowVectors();
81+
82+
return count($rowVectors) === 1 ? array_pop($rowVectors) : null;
83+
}
84+
85+
private function getRowVectors(): array
7986
{
8087
$rowVectors = [];
8188
for ($index = 0; $index < $this->argumentCount; ++$index) {
@@ -87,14 +94,14 @@ public function getRowVectors(): array
8794
return $rowVectors;
8895
}
8996

90-
public function getSingleRowVector(): ?int
97+
public function getSingleColumnVector(): ?int
9198
{
92-
$rowVectors = $this->getRowVectors();
99+
$columnVectors = $this->getColumnVectors();
93100

94-
return count($rowVectors) === 1 ? array_pop($rowVectors) : null;
101+
return count($columnVectors) === 1 ? array_pop($columnVectors) : null;
95102
}
96103

97-
public function getColumnVectors(): array
104+
private function getColumnVectors(): array
98105
{
99106
$columnVectors = [];
100107
for ($index = 0; $index < $this->argumentCount; ++$index) {
@@ -106,11 +113,42 @@ public function getColumnVectors(): array
106113
return $columnVectors;
107114
}
108115

109-
public function getSingleColumnVector(): ?int
116+
public function getMatrixPair(): array
110117
{
111-
$columnVectors = $this->getColumnVectors();
118+
for ($i = 0; $i < ($this->argumentCount - 1); ++$i) {
119+
for ($j = $i + 1; $j < $this->argumentCount; ++$j) {
120+
if (isset($this->rows[$i]) && isset($this->rows[$j])) {
121+
return [$i, $j];
122+
}
123+
}
124+
}
112125

113-
return count($columnVectors) === 1 ? array_pop($columnVectors) : null;
126+
return [];
127+
}
128+
129+
public function isVector(int $argument): bool
130+
{
131+
return $this->rows[$argument] === 1 || $this->columns[$argument] === 1;
132+
}
133+
134+
public function isRowVector(int $argument): bool
135+
{
136+
return $this->rows[$argument] === 1;
137+
}
138+
139+
public function isColumnVector(int $argument): bool
140+
{
141+
return $this->columns[$argument] === 1;
142+
}
143+
144+
public function rowCount(int $argument): int
145+
{
146+
return $this->rows[$argument];
147+
}
148+
149+
public function columnCount(int $argument): int
150+
{
151+
return $this->columns[$argument];
114152
}
115153

116154
private function rows(array $arguments): array

tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public function providerAbsArray(): array
4848
return [
4949
'row vector' => [[[1, 0, 1]], '{-1, 0, 1}'],
5050
'column vector' => [[[1], [0], [1]], '{-1; 0; 1}'],
51-
'matrix' => [[[1, 0], [1, 1]], '{-1, 0; 1, -1}'],
51+
'matrix' => [[[1, 0], [1, 1.4]], '{-1, 0; 1, -1.4}'],
5252
];
5353
}
5454
}

0 commit comments

Comments
 (0)