See Release Notes
Long Term Support Release
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 37 if ($singleRowVectorIndex !== null && $singleColumnVectorIndex !== null) { 38 // Basic logic for a single row vector and a single column vector 39 return self::evaluateVectorPair($method, $singleRowVectorIndex, $singleColumnVectorIndex, ...$arguments); 40 } 41 42 $matrixPair = self::$arrayArgumentHelper->getMatrixPair(); 43 if ($matrixPair !== []) { 44 if ( 45 (self::$arrayArgumentHelper->isVector($matrixPair[0]) === true && 46 self::$arrayArgumentHelper->isVector($matrixPair[1]) === false) || 47 (self::$arrayArgumentHelper->isVector($matrixPair[0]) === false && 48 self::$arrayArgumentHelper->isVector($matrixPair[1]) === true) 49 ) { 50 // Logic for a matrix and a vector (row or column) 51 return self::evaluateVectorMatrixPair($method, $matrixPair, ...$arguments); 52 } 53 // Logic for matrix/matrix, column vector/column vector or row vector/row vector 54 return self::evaluateMatrixPair($method, $matrixPair, ...$arguments); 55 } 56 57 // Still need to work out the logic for more than two array arguments, 58 // For the moment, we're throwing an Exception when we initialise the ArrayArgumentHelper 59 return ['#VALUE!']; 60 } 61 62 /** 63 * @param mixed ...$arguments 64 */ 65 private static function evaluateVectorMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array 66 { 67 $matrix2 = array_pop($matrixIndexes); 68 /** @var array $matrixValues2 */ 69 $matrixValues2 = $arguments[$matrix2]; 70 $matrix1 = array_pop($matrixIndexes); 71 /** @var array $matrixValues1 */ 72 $matrixValues1 = $arguments[$matrix1]; 73 74 $rows = min(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2])); 75 $columns = min(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2])); 76 77 if ($rows === 1) { 78 $rows = max(array_map([self::$arrayArgumentHelper, 'rowCount'], [$matrix1, $matrix2])); 79 } 80 if ($columns === 1) { 81 $columns = max(array_map([self::$arrayArgumentHelper, 'columnCount'], [$matrix1, $matrix2])); 82 } 83 84 $result = []; 85 for ($rowIndex = 0; $rowIndex < $rows; ++$rowIndex) { 86 for ($columnIndex = 0; $columnIndex < $columns; ++$columnIndex) { 87 $rowIndex1 = self::$arrayArgumentHelper->isRowVector($matrix1) ? 0 : $rowIndex; 88 $columnIndex1 = self::$arrayArgumentHelper->isColumnVector($matrix1) ? 0 : $columnIndex; 89 $value1 = $matrixValues1[$rowIndex1][$columnIndex1]; 90 $rowIndex2 = self::$arrayArgumentHelper->isRowVector($matrix2) ? 0 : $rowIndex; 91 $columnIndex2 = self::$arrayArgumentHelper->isColumnVector($matrix2) ? 0 : $columnIndex; 92 $value2 = $matrixValues2[$rowIndex2][$columnIndex2]; 93 $arguments[$matrix1] = $value1; 94 $arguments[$matrix2] = $value2; 95 96 $result[$rowIndex][$columnIndex] = $method(...$arguments); 97 } 98 } 99 100 return $result; 101 } 102 103 /** 104 * @param mixed ...$arguments 105 */ 106 private static function evaluateMatrixPair(callable $method, array $matrixIndexes, ...$arguments): array 107 { 108 $matrix2 = array_pop($matrixIndexes); 109 /** @var array $matrixValues2 */ 110 $matrixValues2 = $arguments[$matrix2]; 111 $matrix1 = array_pop($matrixIndexes); 112 /** @var array $matrixValues1 */ 113 $matrixValues1 = $arguments[$matrix1]; 114 115 $result = []; 116 foreach ($matrixValues1 as $rowIndex => $row) { 117 foreach ($row as $columnIndex => $value1) { 118 if (isset($matrixValues2[$rowIndex][$columnIndex]) === false) { 119 continue; 120 } 121 122 $value2 = $matrixValues2[$rowIndex][$columnIndex]; 123 $arguments[$matrix1] = $value1; 124 $arguments[$matrix2] = $value2; 125 126 $result[$rowIndex][$columnIndex] = $method(...$arguments); 127 } 128 } 129 130 return $result; 131 } 132 133 /** 134 * @param mixed ...$arguments 135 */ 136 private static function evaluateVectorPair(callable $method, int $rowIndex, int $columnIndex, ...$arguments): array 137 { 138 $rowVector = Functions::flattenArray($arguments[$rowIndex]); 139 $columnVector = Functions::flattenArray($arguments[$columnIndex]); 140 141 $result = []; 142 foreach ($columnVector as $column) { 143 $rowResults = []; 144 foreach ($rowVector as $row) { 145 $arguments[$rowIndex] = $row; 146 $arguments[$columnIndex] = $column; 147 148 $rowResults[] = $method(...$arguments); 149 } 150 $result[] = $rowResults; 151 } 152 153 return $result; 154 } 155 156 /** 157 * Note, offset is from 1 (for the first argument) rather than from 0. 158 * 159 * @param mixed ...$arguments 160 */ 161 private static function evaluateNthArgumentAsArray(callable $method, int $nthArgument, ...$arguments): array 162 { 163 $values = array_slice($arguments, $nthArgument - 1, 1); 164 /** @var array $values */ 165 $values = array_pop($values); 166 167 $result = []; 168 foreach ($values as $value) { 169 $arguments[$nthArgument - 1] = $value; 170 $result[] = $method(...$arguments); 171 } 172 173 return $result; 174 } 175 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body