Skip to content

Commit 54e6ebe

Browse files
author
MarkBaker
committed
Refactoring of the processor
1 parent 3d5b46e commit 54e6ebe

File tree

2 files changed

+177
-158
lines changed

2 files changed

+177
-158
lines changed

src/PhpSpreadsheet/Calculation/ArrayEnabled.php

+3-158
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PhpOffice\PhpSpreadsheet\Calculation;
44

55
use PhpOffice\PhpSpreadsheet\Calculation\Engine\ArrayArgumentHelper;
6+
use PhpOffice\PhpSpreadsheet\Calculation\Engine\ArrayArgumentProcessor;
67

78
trait ArrayEnabled
89
{
@@ -37,7 +38,7 @@ protected static function evaluateArrayArguments(callable $method, ...$arguments
3738
self::initialiseHelper($arguments);
3839
$arguments = self::$arrayArgumentHelper->arguments();
3940

40-
return self::processArguments($method, ...$arguments);
41+
return ArrayArgumentProcessor::processArguments(self::$arrayArgumentHelper, $method, ...$arguments);
4142
}
4243

4344
/**
@@ -50,162 +51,6 @@ protected static function evaluateArrayArgumentsSubset(callable $method, int $li
5051
$arguments = self::$arrayArgumentHelper->arguments();
5152
$arguments = array_merge($arguments, $trailingArguments);
5253

53-
return self::processArguments($method, ...$arguments);
54-
}
55-
56-
/**
57-
* @param mixed ...$arguments
58-
*/
59-
private static function processArguments(callable $method, ...$arguments): array
60-
{
61-
if (self::$arrayArgumentHelper->hasArrayArgument() === false) {
62-
return [$method(...$arguments)];
63-
}
64-
65-
if (self::$arrayArgumentHelper->arrayArguments() === 1) {
66-
$nthArgument = self::$arrayArgumentHelper->getFirstArrayArgumentNumber();
67-
68-
return self::evaluateNthArgumentAsArray($method, $nthArgument, ...$arguments);
69-
}
70-
71-
$singleRowVectorIndex = self::$arrayArgumentHelper->getSingleRowVector();
72-
$singleColumnVectorIndex = self::$arrayArgumentHelper->getSingleColumnVector();
73-
if ($singleRowVectorIndex !== null && $singleColumnVectorIndex !== null) {
74-
// Basic logic for a single row vector and a single column vector
75-
return self::evaluateVectorPair($method, $singleRowVectorIndex, $singleColumnVectorIndex, ...$arguments);
76-
}
77-
78-
$matrixPair = self::$arrayArgumentHelper->getMatrixPair();
79-
if ($matrixPair !== []) {
80-
if (
81-
(self::$arrayArgumentHelper->isVector($matrixPair[0]) === true &&
82-
self::$arrayArgumentHelper->isVector($matrixPair[1]) === false) ||
83-
(self::$arrayArgumentHelper->isVector($matrixPair[0]) === false &&
84-
self::$arrayArgumentHelper->isVector($matrixPair[1]) === true)
85-
) {
86-
// Logic for a matrix and a vector (row or column)
87-
return self::evaluateVectorMatrixPair($method, $matrixPair, ...$arguments);
88-
}
89-
// Logic for matrix/matrix, column vector/column vector or row vector/row vector
90-
return self::evaluateMatrixPair($method, $matrixPair, ...$arguments);
91-
}
92-
93-
// Still need to work out the logic for more than two array arguments,
94-
// For the moment, we're throwing an Exception when we initialise the ArrayArgumentHelper
95-
return ['#VALUE!'];
96-
}
97-
98-
/**
99-
* @param mixed ...$arguments
100-
*/
101-
private static function evaluateVectorMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array
102-
{
103-
$matrix2 = array_pop($matrixIndexes);
104-
/** @var array $matrixValues2 */
105-
$matrixValues2 = $arguments[$matrix2];
106-
$matrix1 = array_pop($matrixIndexes);
107-
/** @var array $matrixValues1 */
108-
$matrixValues1 = $arguments[$matrix1];
109-
110-
$rows = min(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
111-
$columns = min(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
112-
113-
if ($rows === 1) {
114-
$rows = max(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
115-
}
116-
if ($columns === 1) {
117-
$columns = max(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
118-
}
119-
120-
$result = [];
121-
for ($rowIndex = 0; $rowIndex < $rows; ++$rowIndex) {
122-
for ($columnIndex = 0; $columnIndex < $columns; ++$columnIndex) {
123-
$rowIndex1 = self::$arrayArgumentHelper->isRowVector($matrix1) ? 0 : $rowIndex;
124-
$columnIndex1 = self::$arrayArgumentHelper->isColumnVector($matrix1) ? 0 : $columnIndex;
125-
$value1 = $matrixValues1[$rowIndex1][$columnIndex1];
126-
$rowIndex2 = self::$arrayArgumentHelper->isRowVector($matrix2) ? 0 : $rowIndex;
127-
$columnIndex2 = self::$arrayArgumentHelper->isColumnVector($matrix2) ? 0 : $columnIndex;
128-
$value2 = $matrixValues2[$rowIndex2][$columnIndex2];
129-
$arguments[$matrix1] = $value1;
130-
$arguments[$matrix2] = $value2;
131-
132-
$result[$rowIndex][$columnIndex] = $method(...$arguments);
133-
}
134-
}
135-
136-
return $result;
137-
}
138-
139-
/**
140-
* @param mixed ...$arguments
141-
*/
142-
private static function evaluateMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array
143-
{
144-
$matrix2 = array_pop($matrixIndexes);
145-
/** @var array $matrixValues2 */
146-
$matrixValues2 = $arguments[$matrix2];
147-
$matrix1 = array_pop($matrixIndexes);
148-
/** @var array $matrixValues1 */
149-
$matrixValues1 = $arguments[$matrix1];
150-
151-
$result = [];
152-
foreach ($matrixValues1 as $rowIndex => $row) {
153-
foreach ($row as $columnIndex => $value1) {
154-
if (isset($matrixValues2[$rowIndex][$columnIndex]) === false) {
155-
continue;
156-
}
157-
158-
$value2 = $matrixValues2[$rowIndex][$columnIndex];
159-
$arguments[$matrix1] = $value1;
160-
$arguments[$matrix2] = $value2;
161-
162-
$result[$rowIndex][$columnIndex] = $method(...$arguments);
163-
}
164-
}
165-
166-
return $result;
167-
}
168-
169-
/**
170-
* @param mixed ...$arguments
171-
*/
172-
private static function evaluateVectorPair(callable $method, int $rowIndex, int $columnIndex, ...$arguments): array
173-
{
174-
$rowVector = Functions::flattenArray($arguments[$rowIndex]);
175-
$columnVector = Functions::flattenArray($arguments[$columnIndex]);
176-
177-
$result = [];
178-
foreach ($columnVector as $column) {
179-
$rowResults = [];
180-
foreach ($rowVector as $row) {
181-
$arguments[$rowIndex] = $row;
182-
$arguments[$columnIndex] = $column;
183-
184-
$rowResults[] = $method(...$arguments);
185-
}
186-
$result[] = $rowResults;
187-
}
188-
189-
return $result;
190-
}
191-
192-
/**
193-
* Note, offset is from 1 (for the first argument) rather than from 0.
194-
*
195-
* @param mixed ...$arguments
196-
*/
197-
private static function evaluateNthArgumentAsArray(callable $method, int $nthArgument, ...$arguments): array
198-
{
199-
$values = array_slice($arguments, $nthArgument - 1, 1);
200-
/** @var array $values */
201-
$values = array_pop($values);
202-
203-
$result = [];
204-
foreach ($values as $value) {
205-
$arguments[$nthArgument - 1] = $value;
206-
$result[] = $method(...$arguments);
207-
}
208-
209-
return $result;
54+
return ArrayArgumentProcessor::processArguments(self::$arrayArgumentHelper, $method, ...$arguments);
21055
}
21156
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet\Calculation\Engine;
4+
5+
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
6+
7+
class ArrayArgumentProcessor
8+
{
9+
/**
10+
* @var ArrayArgumentHelper
11+
*/
12+
private static $arrayArgumentHelper;
13+
14+
/**
15+
* @param mixed ...$arguments
16+
*/
17+
public static function processArguments(
18+
ArrayArgumentHelper $arrayArgumentHelper,
19+
callable $method,
20+
...$arguments
21+
): array {
22+
self::$arrayArgumentHelper = $arrayArgumentHelper;
23+
24+
if (self::$arrayArgumentHelper->hasArrayArgument() === false) {
25+
return [$method(...$arguments)];
26+
}
27+
28+
if (self::$arrayArgumentHelper->arrayArguments() === 1) {
29+
$nthArgument = self::$arrayArgumentHelper->getFirstArrayArgumentNumber();
30+
31+
return self::evaluateNthArgumentAsArray($method, $nthArgument, ...$arguments);
32+
}
33+
34+
$singleRowVectorIndex = self::$arrayArgumentHelper->getSingleRowVector();
35+
$singleColumnVectorIndex = self::$arrayArgumentHelper->getSingleColumnVector();
36+
if ($singleRowVectorIndex !== null && $singleColumnVectorIndex !== null) {
37+
// Basic logic for a single row vector and a single column vector
38+
return self::evaluateVectorPair($method, $singleRowVectorIndex, $singleColumnVectorIndex, ...$arguments);
39+
}
40+
41+
$matrixPair = self::$arrayArgumentHelper->getMatrixPair();
42+
if ($matrixPair !== []) {
43+
if (
44+
(self::$arrayArgumentHelper->isVector($matrixPair[0]) === true &&
45+
self::$arrayArgumentHelper->isVector($matrixPair[1]) === false) ||
46+
(self::$arrayArgumentHelper->isVector($matrixPair[0]) === false &&
47+
self::$arrayArgumentHelper->isVector($matrixPair[1]) === true)
48+
) {
49+
// Logic for a matrix and a vector (row or column)
50+
return self::evaluateVectorMatrixPair($method, $matrixPair, ...$arguments);
51+
}
52+
// Logic for matrix/matrix, column vector/column vector or row vector/row vector
53+
return self::evaluateMatrixPair($method, $matrixPair, ...$arguments);
54+
}
55+
56+
// Still need to work out the logic for more than two array arguments,
57+
// For the moment, we're throwing an Exception when we initialise the ArrayArgumentHelper
58+
return ['#VALUE!'];
59+
}
60+
61+
/**
62+
* @param mixed ...$arguments
63+
*/
64+
private static function evaluateVectorMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array
65+
{
66+
$matrix2 = array_pop($matrixIndexes);
67+
/** @var array $matrixValues2 */
68+
$matrixValues2 = $arguments[$matrix2];
69+
$matrix1 = array_pop($matrixIndexes);
70+
/** @var array $matrixValues1 */
71+
$matrixValues1 = $arguments[$matrix1];
72+
73+
$rows = min(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
74+
$columns = min(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
75+
76+
if ($rows === 1) {
77+
$rows = max(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2]));
78+
}
79+
if ($columns === 1) {
80+
$columns = max(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2]));
81+
}
82+
83+
$result = [];
84+
for ($rowIndex = 0; $rowIndex < $rows; ++$rowIndex) {
85+
for ($columnIndex = 0; $columnIndex < $columns; ++$columnIndex) {
86+
$rowIndex1 = self::$arrayArgumentHelper->isRowVector($matrix1) ? 0 : $rowIndex;
87+
$columnIndex1 = self::$arrayArgumentHelper->isColumnVector($matrix1) ? 0 : $columnIndex;
88+
$value1 = $matrixValues1[$rowIndex1][$columnIndex1];
89+
$rowIndex2 = self::$arrayArgumentHelper->isRowVector($matrix2) ? 0 : $rowIndex;
90+
$columnIndex2 = self::$arrayArgumentHelper->isColumnVector($matrix2) ? 0 : $columnIndex;
91+
$value2 = $matrixValues2[$rowIndex2][$columnIndex2];
92+
$arguments[$matrix1] = $value1;
93+
$arguments[$matrix2] = $value2;
94+
95+
$result[$rowIndex][$columnIndex] = $method(...$arguments);
96+
}
97+
}
98+
99+
return $result;
100+
}
101+
102+
/**
103+
* @param mixed ...$arguments
104+
*/
105+
private static function evaluateMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array
106+
{
107+
$matrix2 = array_pop($matrixIndexes);
108+
/** @var array $matrixValues2 */
109+
$matrixValues2 = $arguments[$matrix2];
110+
$matrix1 = array_pop($matrixIndexes);
111+
/** @var array $matrixValues1 */
112+
$matrixValues1 = $arguments[$matrix1];
113+
114+
$result = [];
115+
foreach ($matrixValues1 as $rowIndex => $row) {
116+
foreach ($row as $columnIndex => $value1) {
117+
if (isset($matrixValues2[$rowIndex][$columnIndex]) === false) {
118+
continue;
119+
}
120+
121+
$value2 = $matrixValues2[$rowIndex][$columnIndex];
122+
$arguments[$matrix1] = $value1;
123+
$arguments[$matrix2] = $value2;
124+
125+
$result[$rowIndex][$columnIndex] = $method(...$arguments);
126+
}
127+
}
128+
129+
return $result;
130+
}
131+
132+
/**
133+
* @param mixed ...$arguments
134+
*/
135+
private static function evaluateVectorPair(callable $method, int $rowIndex, int $columnIndex, ...$arguments): array
136+
{
137+
$rowVector = Functions::flattenArray($arguments[$rowIndex]);
138+
$columnVector = Functions::flattenArray($arguments[$columnIndex]);
139+
140+
$result = [];
141+
foreach ($columnVector as $column) {
142+
$rowResults = [];
143+
foreach ($rowVector as $row) {
144+
$arguments[$rowIndex] = $row;
145+
$arguments[$columnIndex] = $column;
146+
147+
$rowResults[] = $method(...$arguments);
148+
}
149+
$result[] = $rowResults;
150+
}
151+
152+
return $result;
153+
}
154+
155+
/**
156+
* Note, offset is from 1 (for the first argument) rather than from 0.
157+
*
158+
* @param mixed ...$arguments
159+
*/
160+
private static function evaluateNthArgumentAsArray(callable $method, int $nthArgument, ...$arguments): array
161+
{
162+
$values = array_slice($arguments, $nthArgument - 1, 1);
163+
/** @var array $values */
164+
$values = array_pop($values);
165+
166+
$result = [];
167+
foreach ($values as $value) {
168+
$arguments[$nthArgument - 1] = $value;
169+
$result[] = $method(...$arguments);
170+
}
171+
172+
return $result;
173+
}
174+
}

0 commit comments

Comments
 (0)