diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c9762340b..364905f71 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,6 +1,2 @@ parameters: ignoreErrors: - - - message: "#^Binary operation \"/\" between float and array\\|float\\|int\\|string results in an error\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php index 7e55c9768..0af421143 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php @@ -25,7 +25,7 @@ class TimeValue * Excel Function: * TIMEVALUE(timeValue) * - * @param null|array|bool|int|string $timeValue A text string that represents a time in any one of the Microsoft + * @param null|array|bool|float|int|string $timeValue A text string that represents a time in any one of the Microsoft * Excel time formats; for example, "6:45 PM" and "18:45" text strings * within quotation marks that represent time. * Date information in time_text is ignored. @@ -36,7 +36,7 @@ class TimeValue * If an array of numbers is passed as the argument, then the returned result will also be an array * with the same dimensions */ - public static function fromString(null|array|string|int|bool $timeValue): array|string|Datetime|int|float + public static function fromString(null|array|string|int|bool|float $timeValue): array|string|Datetime|int|float { if (is_array($timeValue)) { return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $timeValue); diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php b/src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php index 170b4b2f5..99eb05a5a 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php @@ -40,7 +40,14 @@ class Combinations return $e->getMessage(); } - return round(Factorial::fact($numObjs) / Factorial::fact($numObjs - $numInSet)) / Factorial::fact($numInSet); // @phpstan-ignore-line + /** @var float */ + $quotient = Factorial::fact($numObjs); + /** @var float */ + $divisor1 = Factorial::fact($numObjs - $numInSet); + /** @var float */ + $divisor2 = Factorial::fact($numInSet); + + return round($quotient / ($divisor1 * $divisor2)); } /** @@ -84,8 +91,13 @@ class Combinations return $e->getMessage(); } - return round( - Factorial::fact($numObjs + $numInSet - 1) / Factorial::fact($numObjs - 1) // @phpstan-ignore-line - ) / Factorial::fact($numInSet); + /** @var float */ + $quotient = Factorial::fact($numObjs + $numInSet - 1); + /** @var float */ + $divisor1 = Factorial::fact($numObjs - 1); + /** @var float */ + $divisor2 = Factorial::fact($numInSet); + + return round($quotient / ($divisor1 * $divisor2)); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php index 41f641fe0..06e3b798d 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php @@ -46,16 +46,17 @@ class Permutations if ($numObjs < $numInSet) { return ExcelError::NAN(); } + /** @var float|int|string */ $result1 = MathTrig\Factorial::fact($numObjs); if (is_string($result1)) { return $result1; } + /** @var float|int|string */ $result2 = MathTrig\Factorial::fact($numObjs - $numInSet); if (is_string($result2)) { return $result2; } - // phpstan thinks result1 and result2 can be arrays; they can't. - $result = round($result1 / $result2); // @phpstan-ignore-line + $result = round($result1 / $result2); return IntOrFloat::evaluate($result); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php index d503e8e05..365001fd6 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php @@ -148,7 +148,7 @@ class Trends * @param mixed[] $newValues Values of X for which we want to find Y * @param mixed $const A logical (boolean) value specifying whether to force the intersect to equal 0 or not * - * @return float[] + * @return array>> */ public static function GROWTH(array $yValues, array $xValues = [], array $newValues = [], mixed $const = true): array { @@ -167,7 +167,7 @@ class Trends $returnArray[0][] = [$bestFitExponential->getValueOfYForX($xValue)]; } - return $returnArray; //* @phpstan-ignore-line + return $returnArray; } /** @@ -401,7 +401,7 @@ class Trends * @param mixed[] $newValues Values of X for which we want to find Y * @param mixed $const A logical (boolean) value specifying whether to force the intersect to equal 0 or not * - * @return float[] + * @return array>> */ public static function TREND(array $yValues, array $xValues = [], array $newValues = [], mixed $const = true): array { @@ -420,6 +420,6 @@ class Trends $returnArray[0][] = [$bestFitLinear->getValueOfYForX($xValue)]; } - return $returnArray; //* @phpstan-ignore-line + return $returnArray; } } diff --git a/src/PhpSpreadsheet/Calculation/TextData/Format.php b/src/PhpSpreadsheet/Calculation/TextData/Format.php index 67101ca1d..32df63eb5 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Format.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Format.php @@ -126,8 +126,9 @@ class Format $format = Helpers::extractString($format); if (!is_numeric($value) && Date::isDateTimeFormatCode($format)) { - // @phpstan-ignore-next-line - $value = DateTimeExcel\DateValue::fromString($value) + DateTimeExcel\TimeValue::fromString($value); + $value1 = DateTimeExcel\DateValue::fromString($value); + $value2 = DateTimeExcel\TimeValue::fromString($value); + $value = (is_numeric($value1) && is_numeric($value2)) ? ($value1 + $value2) : (is_numeric($value1) ? $value2 : $value1); } return (string) NumberFormat::toFormattedString($value, $format); diff --git a/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php b/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php index 9cd2e0fa4..08bb7ae67 100644 --- a/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php +++ b/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php @@ -63,7 +63,9 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder // Convert value to number $sign = ($matches['PrefixedSign'] ?? $matches['PrefixedSign2'] ?? $matches['PostfixedSign']) ?? null; $currencyCode = $matches['PrefixedCurrency'] ?? $matches['PostfixedCurrency']; - $value = (float) ($sign . trim(str_replace([$decimalSeparatorNoPreg, $currencyCode, ' ', '-'], ['.', '', '', ''], preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value)))); // @phpstan-ignore-line + /** @var string */ + $temp = str_replace([$decimalSeparatorNoPreg, $currencyCode, ' ', '-'], ['.', '', '', ''], preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value)); + $value = (float) ($sign . trim($temp)); return $this->setCurrency($value, $cell, $currencyCode ?? ''); } diff --git a/src/PhpSpreadsheet/Document/Properties.php b/src/PhpSpreadsheet/Document/Properties.php index 2a4664ecd..576216918 100644 --- a/src/PhpSpreadsheet/Document/Properties.php +++ b/src/PhpSpreadsheet/Document/Properties.php @@ -140,9 +140,9 @@ class Properties return $this; } - private static function intOrFloatTimestamp(null|float|int|string $timestamp): float|int + private static function intOrFloatTimestamp(null|bool|float|int|string $timestamp): float|int { - if ($timestamp === null) { + if ($timestamp === null || is_bool($timestamp)) { $timestamp = (float) (new DateTime())->format('U'); } elseif (is_string($timestamp)) { if (is_numeric($timestamp)) { @@ -468,7 +468,7 @@ class Properties case self::PROPERTY_TYPE_FLOAT: return (float) $propertyValue; case self::PROPERTY_TYPE_DATE: - return self::intOrFloatTimestamp($propertyValue); // @phpstan-ignore-line + return self::intOrFloatTimestamp($propertyValue); case self::PROPERTY_TYPE_BOOLEAN: return is_bool($propertyValue) ? $propertyValue : ($propertyValue === 'true'); default: // includes string diff --git a/src/PhpSpreadsheet/HashTable.php b/src/PhpSpreadsheet/HashTable.php index c306cdb39..94c4836bc 100644 --- a/src/PhpSpreadsheet/HashTable.php +++ b/src/PhpSpreadsheet/HashTable.php @@ -26,7 +26,7 @@ class HashTable * * @param T[] $source Optional source array to create HashTable from */ - public function __construct(?array $source = null) + public function __construct(?array $source = []) { if ($source !== null) { // Create HashTable diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index a5c8837e9..a5436ccdb 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -1002,6 +1002,7 @@ class Xlsx extends BaseReader if (isset($item->formula1)) { $childNode = $node->addChild('formula1'); if ($childNode !== null) { // null should never happen + // see https://github.com/phpstan/phpstan/issues/8236 $childNode[0] = (string) $item->formula1->children(Namespaces::DATA_VALIDATIONS2)->f; // @phpstan-ignore-line } } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index b649c34c0..94d9c6af5 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -574,6 +574,7 @@ class Chart $multiSeriesType = null; $smoothLine = false; $seriesLabel = $seriesCategory = $seriesValues = $plotOrder = $seriesBubbles = []; + $plotDirection = null; $seriesDetailSet = $chartDetail->children($this->cNamespace); foreach ($seriesDetailSet as $seriesDetailKey => $seriesDetails) { @@ -604,11 +605,16 @@ class Chart break; case 'order': $seriesOrder = self::getAttributeInteger($seriesDetail, 'val'); - $plotOrder[$seriesIndex] = $seriesOrder; + if ($seriesOrder !== null) { + $plotOrder[$seriesIndex] = $seriesOrder; + } break; case 'tx': - $seriesLabel[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail); + $temp = $this->chartDataSeriesValueSet($seriesDetail); + if ($temp !== null) { + $seriesLabel[$seriesIndex] = $temp; + } break; case 'spPr': @@ -685,27 +691,42 @@ class Chart break; case 'smooth': - $smoothLine = self::getAttributeBoolean($seriesDetail, 'val'); + $smoothLine = self::getAttributeBoolean($seriesDetail, 'val') ?? false; break; case 'cat': - $seriesCategory[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail); + $temp = $this->chartDataSeriesValueSet($seriesDetail); + if ($temp !== null) { + $seriesCategory[$seriesIndex] = $temp; + } break; case 'val': - $seriesValues[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize"); + $temp = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize"); + if ($temp !== null) { + $seriesValues[$seriesIndex] = $temp; + } break; case 'xVal': - $seriesCategory[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize"); + $temp = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize"); + if ($temp !== null) { + $seriesCategory[$seriesIndex] = $temp; + } break; case 'yVal': - $seriesValues[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize"); + $temp = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize"); + if ($temp !== null) { + $seriesValues[$seriesIndex] = $temp; + } break; case 'bubbleSize': - $seriesBubbles[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize"); + $seriesBubble = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize"); + if ($seriesBubble !== null) { + $seriesBubbles[$seriesIndex] = $seriesBubble; + } break; case 'bubble3D': @@ -819,9 +840,7 @@ class Chart } } } - /** @phpstan-ignore-next-line */ - $series = new DataSeries($plotType, $multiSeriesType, $plotOrder, $seriesLabel, $seriesCategory, $seriesValues, $smoothLine); - /** @phpstan-ignore-next-line */ + $series = new DataSeries($plotType, $multiSeriesType, $plotOrder, $seriesLabel, $seriesCategory, $seriesValues, $plotDirection, $smoothLine); $series->setPlotBubbleSizes($seriesBubbles); return $series; diff --git a/src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer/BSE.php b/src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer/BSE.php index 8ea6fac40..0f5bf31d7 100644 --- a/src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer/BSE.php +++ b/src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer/BSE.php @@ -19,9 +19,9 @@ class BSE /** * The parent BLIP Store Entry Container. - * Property is never currently read. + * Property is currently unused. */ - private BstoreContainer $parent; // @phpstan-ignore-line + private BstoreContainer $parent; /** * The BLIP (Big Large Image or Picture). @@ -43,6 +43,11 @@ class BSE $this->parent = $parent; } + public function getParent(): BstoreContainer + { + return $this->parent; + } + /** * Get the BLIP. */ diff --git a/src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php b/src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php index c7e168044..3435c4f58 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php +++ b/src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php @@ -265,8 +265,12 @@ class NumberFormatter extends BaseFormatter public static function padValue(string $value, string $baseFormat): string { - /** @phpstan-ignore-next-line */ - [$preDecimal, $postDecimal] = preg_split('/\.(?=(?:[^"]*"[^"]*")*[^"]*\Z)/miu', $baseFormat . '.?'); + $preDecimal = $postDecimal = ''; + $pregArray = preg_split('/\.(?=(?:[^"]*"[^"]*")*[^"]*\Z)/miu', $baseFormat . '.?'); + if (is_array($pregArray)) { + $preDecimal = $pregArray[0] ?? ''; + $postDecimal = $pregArray[1] ?? ''; + } $length = strlen($value); if (str_contains($postDecimal, '?')) { diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter.php b/src/PhpSpreadsheet/Worksheet/AutoFilter.php index e4e79f945..afaa345e2 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter.php @@ -1001,9 +1001,10 @@ class AutoFilter implements Stringable foreach ($columnFilterTests as $columnID => $columnFilterTest) { $cellValue = $this->workSheet->getCell($columnID . $row)->getCalculatedValue(); // Execute the filter test + /** @var callable */ + $temp = [self::class, $columnFilterTest['method']]; $result // $result && // phpstan says $result is always true here - // @phpstan-ignore-next-line - = call_user_func_array([self::class, $columnFilterTest['method']], [$cellValue, $columnFilterTest['arguments']]); + = call_user_func_array($temp, [$cellValue, $columnFilterTest['arguments']]); // If filter test has resulted in FALSE, exit the loop straightaway rather than running any more tests if (!$result) { break; diff --git a/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php b/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php index 3b7c36ba3..fa6157db1 100644 --- a/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php +++ b/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php @@ -217,7 +217,7 @@ class MemoryDrawing extends BaseDrawing if (function_exists('getimagesize')) { $imageSize = @getimagesize($temporaryFileName); if (is_array($imageSize)) { - $mimeType = $imageSize['mime'] ?? null; // @phpstan-ignore-line + $mimeType = $imageSize['mime']; return self::supportedMimeTypes($mimeType); } diff --git a/src/PhpSpreadsheet/Worksheet/Table.php b/src/PhpSpreadsheet/Worksheet/Table.php index e2ebf478f..44ee36ff8 100644 --- a/src/PhpSpreadsheet/Worksheet/Table.php +++ b/src/PhpSpreadsheet/Worksheet/Table.php @@ -194,8 +194,8 @@ class Table implements Stringable foreach ($spreadsheet->getNamedFormulae() as $namedFormula) { $formula = $namedFormula->getValue(); if (preg_match($pattern, $formula) === 1) { - $formula = preg_replace($pattern, "{$newName}[", $formula); - $namedFormula->setValue($formula); // @phpstan-ignore-line + $formula = preg_replace($pattern, "{$newName}[", $formula) ?? ''; + $namedFormula->setValue($formula); } } } diff --git a/src/PhpSpreadsheet/Worksheet/Table/Column.php b/src/PhpSpreadsheet/Worksheet/Table/Column.php index e08ffcc6d..8f8f55b95 100644 --- a/src/PhpSpreadsheet/Worksheet/Table/Column.php +++ b/src/PhpSpreadsheet/Worksheet/Table/Column.php @@ -232,8 +232,8 @@ class Column foreach ($spreadsheet->getNamedFormulae() as $namedFormula) { $formula = $namedFormula->getValue(); if (preg_match($pattern, $formula) === 1) { - $formula = preg_replace($pattern, "[$1{$newTitle}]", $formula); - $namedFormula->setValue($formula); // @phpstan-ignore-line + $formula = preg_replace($pattern, "[$1{$newTitle}]", $formula) ?? ''; + $namedFormula->setValue($formula); } } } diff --git a/src/PhpSpreadsheet/Writer/Ods/Meta.php b/src/PhpSpreadsheet/Writer/Ods/Meta.php index be937c256..b47b25539 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Meta.php +++ b/src/PhpSpreadsheet/Writer/Ods/Meta.php @@ -96,7 +96,7 @@ class Meta extends WriterPart case Properties::PROPERTY_TYPE_INTEGER: case Properties::PROPERTY_TYPE_FLOAT: $objWriter->writeAttribute('meta:value-type', 'float'); - $objWriter->writeRawData($propertyValue); // @phpstan-ignore-line + $objWriter->writeRawData((string) $propertyValue); break; case Properties::PROPERTY_TYPE_BOOLEAN: @@ -106,12 +106,12 @@ class Meta extends WriterPart break; case Properties::PROPERTY_TYPE_DATE: $objWriter->writeAttribute('meta:value-type', 'date'); - $dtobj = Date::dateTimeFromTimestamp($propertyValue ?? 0); // @phpstan-ignore-line + $dtobj = Date::dateTimeFromTimestamp((string) ($propertyValue ?? 0)); $objWriter->writeRawData($dtobj->format(DATE_W3C)); break; default: - $objWriter->writeRawData($propertyValue); // @phpstan-ignore-line + $objWriter->writeRawData((string) $propertyValue); break; } diff --git a/src/PhpSpreadsheet/Writer/Xls/Workbook.php b/src/PhpSpreadsheet/Writer/Xls/Workbook.php index 2924454fa..7a31b5f50 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Workbook.php +++ b/src/PhpSpreadsheet/Writer/Xls/Workbook.php @@ -52,12 +52,12 @@ class Workbook extends BIFFwriter */ private Parser $parser; - /** + /* * The BIFF file size for the workbook. Not currently used. * * @see calcSheetOffsets() */ - private int $biffSize; // @phpstan-ignore-line + //private int $biffSize; /** * XF Writers. @@ -159,7 +159,7 @@ class Workbook extends BIFFwriter parent::__construct(); $this->parser = $parser; - $this->biffSize = 0; + //$this->biffSize = 0; $this->palette = []; $this->countryCode = -1; @@ -452,7 +452,7 @@ class Workbook extends BIFFwriter $this->worksheetOffsets[$i] = $offset; $offset += $this->worksheetSizes[$i]; } - $this->biffSize = $offset; + //$this->biffSize = $offset; } /** diff --git a/src/PhpSpreadsheet/Writer/Xlsx.php b/src/PhpSpreadsheet/Writer/Xlsx.php index 4a81ab861..33bcdb5ac 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx.php +++ b/src/PhpSpreadsheet/Writer/Xlsx.php @@ -158,19 +158,12 @@ class Xlsx extends BaseWriter $this->writerPartWorksheet = new Worksheet($this); // Set HashTable variables - // @phpstan-ignore-next-line $this->bordersHashTable = new HashTable(); - // @phpstan-ignore-next-line $this->drawingHashTable = new HashTable(); - // @phpstan-ignore-next-line $this->fillHashTable = new HashTable(); - // @phpstan-ignore-next-line $this->fontHashTable = new HashTable(); - // @phpstan-ignore-next-line $this->numFmtHashTable = new HashTable(); - // @phpstan-ignore-next-line $this->styleHashTable = new HashTable(); - // @phpstan-ignore-next-line $this->stylesConditionalHashTable = new HashTable(); } diff --git a/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php b/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php index 78accd585..e2c63207f 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php @@ -216,7 +216,7 @@ class DocProps extends WriterPart switch ($propertyType) { case Properties::PROPERTY_TYPE_INTEGER: - $objWriter->writeElement('vt:i4', $propertyValue); // @phpstan-ignore-line + $objWriter->writeElement('vt:i4', (string) $propertyValue); break; case Properties::PROPERTY_TYPE_FLOAT: @@ -235,7 +235,7 @@ class DocProps extends WriterPart break; default: - $objWriter->writeElement('vt:lpwstr', $propertyValue); // @phpstan-ignore-line + $objWriter->writeElement('vt:lpwstr', (string) $propertyValue); break; } diff --git a/tests/PhpSpreadsheetTests/Shared/DggContainerTest.php b/tests/PhpSpreadsheetTests/Shared/DggContainerTest.php new file mode 100644 index 000000000..e10478577 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Shared/DggContainerTest.php @@ -0,0 +1,19 @@ +setParent($container); + self::assertSame($container, $bse->getParent()); + } +}