diff --git a/composer.lock b/composer.lock
index 43c4aeaef..7140b853f 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1803,16 +1803,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "2.1.21",
+ "version": "2.1.23",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "1ccf445757458c06a04eb3f803603cb118fe5fa6"
+ "reference": "a34502adbbd5c2366b5a97679848a5ace4f6f2f5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1ccf445757458c06a04eb3f803603cb118fe5fa6",
- "reference": "1ccf445757458c06a04eb3f803603cb118fe5fa6",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a34502adbbd5c2366b5a97679848a5ace4f6f2f5",
+ "reference": "a34502adbbd5c2366b5a97679848a5ace4f6f2f5",
"shasum": ""
},
"require": {
@@ -1857,7 +1857,7 @@
"type": "github"
}
],
- "time": "2025-07-28T19:35:08+00:00"
+ "time": "2025-09-10T11:42:22+00:00"
},
{
"name": "phpstan/phpstan-deprecation-rules",
@@ -5664,7 +5664,7 @@
"ext-zip": "*",
"ext-zlib": "*"
},
- "platform-dev": [],
+ "platform-dev": {},
"platform-overrides": {
"php": "8.1.99"
},
diff --git a/infra/LocaleGenerator.php b/infra/LocaleGenerator.php
index 422c0c97f..d99eb8193 100644
--- a/infra/LocaleGenerator.php
+++ b/infra/LocaleGenerator.php
@@ -327,7 +327,7 @@ class LocaleGenerator
foreach ($cells as $cell) {
if ($cell->getValue() != '') {
$this->log($cell->getRow() . ' -> ' . $cell->getValueString());
- $this->errorCodeMap[$cell->getValue()] = $cell->getRow();
+ $this->errorCodeMap[$cell->getValueString()] = $cell->getRow();
}
}
}
@@ -345,7 +345,7 @@ class LocaleGenerator
if ($this->isFunctionCategoryEntry($cell)) {
if (!empty($cell->getValue())) {
$this->log('CATEGORY: ' . $cell->getValueString());
- $this->functionNameMap[$cell->getValue()] = $cell->getRow();
+ $this->functionNameMap[$cell->getValueString()] = $cell->getRow();
}
continue;
@@ -356,7 +356,7 @@ class LocaleGenerator
$this->functionNameMap[($cell->getValue() ? 'TRUE' : 'FALSE')] = $cell->getRow();
} else {
$this->log($cell->getRow() . ' -> ' . $cell->getValueString());
- $this->functionNameMap[$cell->getValue()] = $cell->getRow();
+ $this->functionNameMap[$cell->getValueString()] = $cell->getRow();
}
}
}
diff --git a/samples/Wizards/NumberFormat/Currency.php b/samples/Wizards/NumberFormat/Currency.php
index 1e1e53cc4..7484d012f 100644
--- a/samples/Wizards/NumberFormat/Currency.php
+++ b/samples/Wizards/NumberFormat/Currency.php
@@ -104,7 +104,7 @@ if (isset($_POST['submit'])) {
$helper->log('Unrecognized currency symbol');
} else {
try {
- $negative = $negatives[$_POST['negative']] ?? CurrencyNegative::minus;
+ $negative = $negatives[$_POST['negative']] ?? CurrencyNegative::minus; //* @phpstan-ignore-line
$wizard = new Wizard\Currency($_POST['currency'], (int) $_POST['decimals'], isset($_POST['thousands']), (bool) $_POST['position']);
$wizard->setNegative($negative);
$mask = $wizard->format();
@@ -118,7 +118,7 @@ if (isset($_POST['submit'])) {
. ', Wizard\Currency::' . (((bool) $_POST['position']) ? 'LEADING_SYMBOL' : 'TRAILING_SYMBOL')
. ');'
);
- $helper->log('$wizard->setNegative(' . $negativesString[$_POST['negative']] . ');');
+ $helper->log('$wizard->setNegative(' . $negativesString[$_POST['negative']] . ');'); //* @phpstan-ignore-line
$helper->log('$mask = $wizard->format();');
$helper->log('
echo (string) $mask;');
$helper->log('
Mask:
');
diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php
index 2e00977df..a210c88cd 100644
--- a/src/PhpSpreadsheet/Calculation/Calculation.php
+++ b/src/PhpSpreadsheet/Calculation/Calculation.php
@@ -1699,7 +1699,7 @@ class Calculation extends CalculationLocale
return $this->raiseFormulaError($e->getMessage(), $e->getCode(), $e);
}
}
- } elseif (!is_numeric($token) && !is_object($token) && isset($token, self::BINARY_OPERATORS[$token])) {
+ } elseif (!is_numeric($token) && !is_object($token) && isset($token, self::BINARY_OPERATORS[$token])) { //* @phpstan-ignore-line
// if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
// We must have two operands, error if we don't
$operand2Data = $stack->pop();
@@ -2879,6 +2879,7 @@ class Calculation extends CalculationLocale
if ($stack->count() > 0) {
$o2 = $stack->last();
if ($o2) {
+ /** @var array{value: string} $o2 */
if (isset(self::CALCULATION_OPERATORS[$o2['value']])) {
$retVal = (self::OPERATOR_PRECEDENCE[$opCharacter] ?? 0) <= self::OPERATOR_PRECEDENCE[$o2['value']];
}
diff --git a/src/PhpSpreadsheet/Calculation/Engine/ArrayArgumentProcessor.php b/src/PhpSpreadsheet/Calculation/Engine/ArrayArgumentProcessor.php
index 7004d0877..687ab1b46 100644
--- a/src/PhpSpreadsheet/Calculation/Engine/ArrayArgumentProcessor.php
+++ b/src/PhpSpreadsheet/Calculation/Engine/ArrayArgumentProcessor.php
@@ -102,7 +102,7 @@ class ArrayArgumentProcessor
}
/**
- * @param mixed[] $matrixIndexes
+ * @param array $matrixIndexes
*
* @return mixed[]
*/
diff --git a/src/PhpSpreadsheet/Calculation/Engine/CyclicReferenceStack.php b/src/PhpSpreadsheet/Calculation/Engine/CyclicReferenceStack.php
index f4806b477..c50fad654 100644
--- a/src/PhpSpreadsheet/Calculation/Engine/CyclicReferenceStack.php
+++ b/src/PhpSpreadsheet/Calculation/Engine/CyclicReferenceStack.php
@@ -21,8 +21,10 @@ class CyclicReferenceStack
/**
* Push a new entry onto the stack.
+ *
+ * @param int|string $value The value to test
*/
- public function push(mixed $value): void
+ public function push($value): void
{
$this->stack[$value] = $value;
}
@@ -38,9 +40,9 @@ class CyclicReferenceStack
/**
* Test to see if a specified entry exists on the stack.
*
- * @param mixed $value The value to test
+ * @param int|string $value The value to test
*/
- public function onStack(mixed $value): bool
+ public function onStack($value): bool
{
return isset($this->stack[$value]);
}
diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php
index 20cdd0697..287e841ca 100644
--- a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php
+++ b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php
@@ -135,14 +135,14 @@ class Matrix
return self::extractRowValue($matrix, $rowKeys, $rowNum);
}
- $columnNum = $columnKeys[--$columnNum];
+ $columnNum = $columnKeys[--$columnNum]; //* @phpstan-ignore-line
if ($rowNum === 0) {
return array_map(
fn ($value): array => [$value],
array_column($matrix, $columnNum)
);
}
- $rowNum = $rowKeys[--$rowNum];
+ $rowNum = $rowKeys[--$rowNum]; //* @phpstan-ignore-line
/** @var mixed[][] $matrix */
return $matrix[$rowNum][$columnNum];
@@ -159,7 +159,7 @@ class Matrix
}
$rowNum = $rowKeys[--$rowNum];
- $row = $matrix[$rowNum];
+ $row = $matrix[$rowNum]; //* @phpstan-ignore-line
if (is_array($row)) {
return [$rowNum => $row];
}
diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Sort.php b/src/PhpSpreadsheet/Calculation/LookupRef/Sort.php
index 352f5c8cd..78a30a4d7 100644
--- a/src/PhpSpreadsheet/Calculation/LookupRef/Sort.php
+++ b/src/PhpSpreadsheet/Calculation/LookupRef/Sort.php
@@ -335,6 +335,7 @@ class Sort extends LookupRefValidations
// Building a new array in the correct (sorted) order works; but may be memory heavy for larger arrays
$sortedArray = [];
foreach ($sortVector as $index) {
+ /** @var int|string $index */
$sortedArray[] = $sortArray[$index];
}
diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php b/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php
index ab58add3a..47c2c9800 100644
--- a/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php
+++ b/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php
@@ -23,7 +23,7 @@ class Arabic
/**
* Recursively calculate the arabic value of a roman numeral.
*
- * @param mixed[] $roman
+ * @param string[] $roman
*/
private static function calculateArabic(array $roman, int &$sum = 0, int $subtract = 0): int
{
diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Averages.php b/src/PhpSpreadsheet/Calculation/Statistical/Averages.php
index 55eb2ae80..588098277 100644
--- a/src/PhpSpreadsheet/Calculation/Statistical/Averages.php
+++ b/src/PhpSpreadsheet/Calculation/Statistical/Averages.php
@@ -163,7 +163,7 @@ class Averages extends AggregateBase
sort($aArgs, SORT_NUMERIC);
$valueCount = $valueCount / 2;
if ($valueCount == floor($valueCount)) {
- $returnValue = ($aArgs[$valueCount--] + $aArgs[$valueCount]) / 2;
+ $returnValue = ($aArgs[$valueCount--] + $aArgs[$valueCount]) / 2; //* @phpstan-ignore-line
} else {
$valueCount = (int) floor($valueCount);
$returnValue = $aArgs[$valueCount];
@@ -243,7 +243,7 @@ class Averages extends AggregateBase
$maxfreqkey = $key;
$maxfreqdatum = $datum;
} elseif ($freq == $maxfreq) {
- if ($frequencyArray[$key]['index'] < $frequencyArray[$maxfreqkey]['index']) {
+ if ($frequencyArray[$key]['index'] < $frequencyArray[$maxfreqkey]['index']) { //* @phpstan-ignore-line
$maxfreqkey = $key;
$maxfreqdatum = $datum;
}
diff --git a/src/PhpSpreadsheet/Chart/DataSeriesValues.php b/src/PhpSpreadsheet/Chart/DataSeriesValues.php
index 78a2bbec3..f37893220 100644
--- a/src/PhpSpreadsheet/Chart/DataSeriesValues.php
+++ b/src/PhpSpreadsheet/Chart/DataSeriesValues.php
@@ -333,16 +333,12 @@ class DataSeriesValues extends Properties
* Method for validating hex color.
*
* @param string $color value for color
- *
- * @return bool true if validation was successful
*/
- private function validateColor(string $color): bool
+ private function validateColor(string $color): void
{
if (!preg_match('/^[a-f0-9]{6}$/i', $color)) {
throw new Exception(sprintf('Invalid hex color for chart series (color: "%s")', $color));
}
-
- return true;
}
/**
diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php
index 3c1ac4f16..29384ff0a 100644
--- a/src/PhpSpreadsheet/Reader/Xls.php
+++ b/src/PhpSpreadsheet/Reader/Xls.php
@@ -140,7 +140,7 @@ class Xls extends XlsBase
/**
* REF structures. Only applies to BIFF8.
*
- * @var mixed[][]
+ * @var array
*/
protected array $ref;
@@ -2022,8 +2022,8 @@ class Xls extends XlsBase
// repeated option flags
// OpenOffice.org documentation 5.21
- $option = ord($recordData[$pos]);
/** @var int $pos */
+ $option = ord($recordData[$pos]);
++$pos;
/** @var int $limitpos */
diff --git a/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php b/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php
index dda8aadb1..76e4235b8 100644
--- a/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php
+++ b/src/PhpSpreadsheet/Reader/Xls/LoadSpreadsheet.php
@@ -549,6 +549,7 @@ class LoadSpreadsheet extends Xls
foreach ($xls->sharedFormulaParts as $cell => $baseCell) {
/** @var int $row */
[$column, $row] = Coordinate::coordinateFromString($cell);
+ /** @var string $baseCell */
if ($xls->getReadFilter()->readCell($column, $row, $xls->phpSheet->getTitle())) {
/** @var string */
$temp = $xls->sharedFormulas[$baseCell];
diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php
index c7c171da2..f8a0b1132 100644
--- a/src/PhpSpreadsheet/Reader/Xlsx.php
+++ b/src/PhpSpreadsheet/Reader/Xlsx.php
@@ -1079,7 +1079,8 @@ class Xlsx extends BaseReader
$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
+ // resolved with Phpstan 2.1.23
+ $childNode[0] = (string) $item->formula1->children(Namespaces::DATA_VALIDATIONS2)->f;
}
}
}
diff --git a/src/PhpSpreadsheet/Reader/Xml/Style/Border.php b/src/PhpSpreadsheet/Reader/Xml/Style/Border.php
index 349eaab60..8a5407d02 100644
--- a/src/PhpSpreadsheet/Reader/Xml/Style/Border.php
+++ b/src/PhpSpreadsheet/Reader/Xml/Style/Border.php
@@ -85,6 +85,7 @@ class Border extends StyleBase
}
}
+ /** @var int|string $borderPosition */
if ($borderPosition) {
$style['borders'][$borderPosition] = $thisBorder;
} elseif ($diagonalDirection) {
@@ -99,6 +100,7 @@ class Border extends StyleBase
/** @return mixed[] */
protected function parsePosition(string $borderStyleValue, string $diagonalDirection): array
{
+ // TODO diagonalDirection seems to return int not string
$borderStyleValue = strtolower($borderStyleValue);
if (in_array($borderStyleValue, self::BORDER_POSITIONS)) {
diff --git a/src/PhpSpreadsheet/Reader/Xml/Style/NumberFormat.php b/src/PhpSpreadsheet/Reader/Xml/Style/NumberFormat.php
index e6fffe176..1ca825a54 100644
--- a/src/PhpSpreadsheet/Reader/Xml/Style/NumberFormat.php
+++ b/src/PhpSpreadsheet/Reader/Xml/Style/NumberFormat.php
@@ -15,7 +15,7 @@ class NumberFormat extends StyleBase
$toFormats = ['-', ' '];
foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
- $styleAttributeValue = str_replace($fromFormats, $toFormats, $styleAttributeValue);
+ $styleAttributeValue = str_replace($fromFormats, $toFormats, (string) $styleAttributeValue);
switch ($styleAttributeValue) {
case 'Short Date':
diff --git a/src/PhpSpreadsheet/Style/Style.php b/src/PhpSpreadsheet/Style/Style.php
index 089c9cccb..feac1cb95 100644
--- a/src/PhpSpreadsheet/Style/Style.php
+++ b/src/PhpSpreadsheet/Style/Style.php
@@ -400,6 +400,7 @@ class Style extends Supervisor
}
// Find existing style by hash.
+ /** @var string $styleHash */
$existingStyle = self::$cachedStyles['styleByHash'][$styleHash] ?? null;
if (!$existingStyle) {
diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php
index 1ee2eff54..441204ca6 100644
--- a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php
+++ b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php
@@ -274,7 +274,8 @@ class Rule
throw new PhpSpreadsheetException('Invalid rule value for column AutoFilter Rule.');
}
// Set the dateTime grouping that we've anticipated
- $this->setGrouping(self::DATE_TIME_GROUPS[$grouping]);
+ // I have no idea what Phpstan is complaining about below
+ $this->setGrouping(self::DATE_TIME_GROUPS[$grouping]); // @phpstan-ignore-line
}
$this->value = $value;
diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php
index cd7c89a3d..7021d8292 100644
--- a/src/PhpSpreadsheet/Worksheet/Worksheet.php
+++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php
@@ -3005,6 +3005,7 @@ class Worksheet
// Loop through rows
foreach ($this->rangeToArrayYieldRows($range, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays) as $rowRef => $rowArray) {
+ /** @var int $rowRef */
$returnValue[$rowRef] = $rowArray;
}
@@ -3040,6 +3041,7 @@ class Worksheet
foreach ($parts as $part) {
// Loop through rows
foreach ($this->rangeToArrayYieldRows($part, $nullValue, $calculateFormulas, $formatData, $returnCellRef, $ignoreHidden, $reduceArrays) as $rowRef => $rowArray) {
+ /** @var int $rowRef */
$returnValue[$rowRef] = $rowArray;
}
}
diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php
index 8ebc4718e..27849bf37 100644
--- a/src/PhpSpreadsheet/Writer/Html.php
+++ b/src/PhpSpreadsheet/Writer/Html.php
@@ -2093,6 +2093,7 @@ class Html extends BaseWriter
// For each of the omitted rows we found above, the affected rowspans should be subtracted by 1
if (isset($this->isSpannedRow[$sheetIndex])) {
foreach ($this->isSpannedRow[$sheetIndex] as $rowIndex) {
+ /** @var int $rowIndex */
$adjustedBaseCells = [];
$c = -1;
$e = $countColumns - 1;
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php b/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
index 09ce162ca..608eadaf0 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
@@ -35,6 +35,7 @@ class StringTable extends WriterPart
foreach ($worksheet->getCellCollection()->getCoordinates() as $coordinate) {
/** @var Cell $cell */
$cell = $worksheet->getCellCollection()->get($coordinate);
+ /** @var null|int|RichText|string */
$cellValue = $cell->getValue();
if (
!is_object($cellValue)
diff --git a/tests/PhpSpreadsheetTests/Issue1449Test.php b/tests/PhpSpreadsheetTests/Issue1449Test.php
index d00b10f6e..211fe52fe 100644
--- a/tests/PhpSpreadsheetTests/Issue1449Test.php
+++ b/tests/PhpSpreadsheetTests/Issue1449Test.php
@@ -7,8 +7,7 @@ use PHPUnit\Framework\TestCase;
class Issue1449Test extends TestCase
{
- /** @var bool */
- private $skipTests = true;
+ protected bool $skipTests = true;
public function testDeleteColumns(): void
{
diff --git a/tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php b/tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php
index 429a2ee86..19392acbf 100644
--- a/tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php
+++ b/tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php
@@ -33,7 +33,6 @@ class GnumericStylesTest extends TestCase
foreach ($expected as $key => $val) {
$covered[$key] = 0;
}
- /** @var mixed[][] */
$tests = $this->providerBorderStyle();
foreach ($tests as $test) {
$covered[$test[0]] = 1;
@@ -88,7 +87,6 @@ class GnumericStylesTest extends TestCase
foreach ($expected as $key => $val) {
$covered[$key] = 0;
}
- /** @var mixed[][] */
$tests = $this->providerHorizontal();
foreach ($tests as $test) {
$covered[$test[0]] = 1;
@@ -117,7 +115,6 @@ class GnumericStylesTest extends TestCase
foreach ($expected as $key => $val) {
$covered[$key] = 0;
}
- /** @var mixed[][] */
$tests = $this->providerUnderline();
foreach ($tests as $test) {
$covered[$test[0]] = 1;
@@ -185,6 +182,7 @@ class GnumericStylesTest extends TestCase
}
}
+ /** @return array */
public static function providerBorderStyle(): array
{
return [
@@ -205,7 +203,7 @@ class GnumericStylesTest extends TestCase
];
}
- /** @return string[][] */
+ /** @return array */
public static function providerFillType(): array
{
return [
@@ -230,6 +228,7 @@ class GnumericStylesTest extends TestCase
];
}
+ /** @return array */
public static function providerHorizontal(): array
{
return [
@@ -243,6 +242,7 @@ class GnumericStylesTest extends TestCase
];
}
+ /** @return array */
public static function providerUnderline(): array
{
return [