Phpstan and Php8 Phase 2 (#2435)

PR #2428 reduced the count of Phpstan errors reported under Php8 from 218 to 13. This PR takes care of those 13, which could not necessarily be handled merely by tweaks to the configuration files.

The commonest problem was that Phpstan under Php7 thinks date_parse can return an array or false, but, under Php8, it thinks it can return only array. The documentation agrees with the Php7 interpretation, but I have not been able to construct a case, in any release of Php, where date_parse returns false. In case of error, it sets elements 'error' and 'error_count' in the returned array. Code is changed to handle either possibility in a manner of which Phpstan will approve.

Other problems are handled through type-hinting.
This commit is contained in:
oleibman 2021-12-09 23:11:19 -08:00 committed by GitHub
parent 81dd743d3f
commit 5240a23117
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 60 additions and 38 deletions

View File

@ -5190,11 +5190,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Shared/StringHelper.php path: src/PhpSpreadsheet/Shared/StringHelper.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:countCharacters\\(\\) should return int but returns int\\|false\\.$#"
count: 1
path: src/PhpSpreadsheet/Shared/StringHelper.php
- -
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:formatNumber\\(\\) should return string but returns array\\|string\\.$#" message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:formatNumber\\(\\) should return string but returns array\\|string\\.$#"
count: 1 count: 1
@ -6970,11 +6965,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php
-
message: "#^Parameter \\#1 \\$ascii of function chr expects int, float given\\.$#"
count: 3
path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php
- -
message: "#^Parameter \\#1 \\$bitmap of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:processBitmap\\(\\) expects string, mixed given\\.$#" message: "#^Parameter \\#1 \\$bitmap of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:processBitmap\\(\\) expects string, mixed given\\.$#"
count: 1 count: 1
@ -7640,11 +7630,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
-
message: "#^Parameter \\#3 \\$namespace of method XMLWriter\\:\\:startElementNs\\(\\) expects string, null given\\.$#"
count: 8
path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php
- -
message: "#^Parameter \\#3 \\$stringTable of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Worksheet\\:\\:writeSheetData\\(\\) expects array\\<string\\>, array\\<string\\>\\|null given\\.$#" message: "#^Parameter \\#3 \\$stringTable of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Worksheet\\:\\:writeSheetData\\(\\) expects array\\<string\\>, array\\<string\\>\\|null given\\.$#"
count: 1 count: 1

View File

@ -3,7 +3,7 @@
$config = []; $config = [];
if (PHP_VERSION_ID < 80000) { if (PHP_VERSION_ID < 80000) {
// Change of signature in PHP 8.0 // GdImage not available before PHP8
$config['parameters']['ignoreErrors'][] = [ $config['parameters']['ignoreErrors'][] = [
'message' => '~^Method .* has invalid return type GdImage\.$~', 'message' => '~^Method .* has invalid return type GdImage\.$~',
'path' => __DIR__ . '/src/PhpSpreadsheet/Shared/Drawing.php', 'path' => __DIR__ . '/src/PhpSpreadsheet/Shared/Drawing.php',
@ -34,6 +34,18 @@ if (PHP_VERSION_ID < 80000) {
'path' => __DIR__ . '/src/PhpSpreadsheet/Writer/Xls/Worksheet.php', 'path' => __DIR__ . '/src/PhpSpreadsheet/Writer/Xls/Worksheet.php',
'count' => 1, 'count' => 1,
]; ];
// Erroneous analysis by Phpstan before PHP8 - 3rd parameter is nullable
$config['parameters']['ignoreErrors'][] = [
'message' => '#^Parameter \\#3 \\$namespace of method XMLWriter\\:\\:startElementNs\\(\\) expects string, null given\\.$#',
'path' => __DIR__ . '/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php',
'count' => 8,
];
// Erroneous analysis by Phpstan before PHP8 - mb_strlen does not return false
$config['parameters']['ignoreErrors'][] = [
'message' => '#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:countCharacters\\(\\) should return int but returns int\\|false\\.$#',
'path' => __DIR__ . '/src/PhpSpreadsheet/Shared/StringHelper.php',
'count' => 1,
];
} }
return $config; return $config;

View File

@ -27,9 +27,9 @@ class Current
public static function today() public static function today()
{ {
$dti = new DateTimeImmutable(); $dti = new DateTimeImmutable();
$dateArray = date_parse($dti->format('c')); $dateArray = Helpers::dateParse($dti->format('c'));
return is_array($dateArray) ? Helpers::returnIn3FormatsArray($dateArray, true) : Functions::VALUE(); return Helpers::dateParseSucceeded($dateArray) ? Helpers::returnIn3FormatsArray($dateArray, true) : Functions::VALUE();
} }
/** /**
@ -52,8 +52,8 @@ class Current
public static function now() public static function now()
{ {
$dti = new DateTimeImmutable(); $dti = new DateTimeImmutable();
$dateArray = date_parse($dti->format('c')); $dateArray = Helpers::dateParse($dti->format('c'));
return is_array($dateArray) ? Helpers::returnIn3FormatsArray($dateArray) : Functions::VALUE(); return Helpers::dateParseSucceeded($dateArray) ? Helpers::returnIn3FormatsArray($dateArray) : Functions::VALUE();
} }
} }

View File

@ -92,13 +92,11 @@ class DateValue
/** /**
* Parse date. * Parse date.
*
* @return array|bool
*/ */
private static function setUpArray(string $dateValue, DateTimeImmutable $dti) private static function setUpArray(string $dateValue, DateTimeImmutable $dti): array
{ {
$PHPDateArray = date_parse($dateValue); $PHPDateArray = Helpers::dateParse($dateValue);
if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) { if (!Helpers::dateParseSucceeded($PHPDateArray)) {
// If original count was 1, we've already returned. // If original count was 1, we've already returned.
// If it was 2, we added another. // If it was 2, we added another.
// Therefore, neither of the first 2 stroks below can fail. // Therefore, neither of the first 2 stroks below can fail.
@ -106,9 +104,9 @@ class DateValue
$testVal2 = strtok('- '); $testVal2 = strtok('- ');
$testVal3 = strtok('- ') ?: $dti->format('Y'); $testVal3 = strtok('- ') ?: $dti->format('Y');
Helpers::adjustYear((string) $testVal1, (string) $testVal2, $testVal3); Helpers::adjustYear((string) $testVal1, (string) $testVal2, $testVal3);
$PHPDateArray = date_parse($testVal1 . '-' . $testVal2 . '-' . $testVal3); $PHPDateArray = Helpers::dateParse($testVal1 . '-' . $testVal2 . '-' . $testVal3);
if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) { if (!Helpers::dateParseSucceeded($PHPDateArray)) {
$PHPDateArray = date_parse($testVal2 . '-' . $testVal1 . '-' . $testVal3); $PHPDateArray = Helpers::dateParse($testVal2 . '-' . $testVal1 . '-' . $testVal3);
} }
} }
@ -118,15 +116,13 @@ class DateValue
/** /**
* Final results. * Final results.
* *
* @param array|bool $PHPDateArray
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag * depending on the value of the ReturnDateType flag
*/ */
private static function finalResults($PHPDateArray, DateTimeImmutable $dti, int $baseYear) private static function finalResults(array $PHPDateArray, DateTimeImmutable $dti, int $baseYear)
{ {
$retValue = Functions::Value(); $retValue = Functions::Value();
if (is_array($PHPDateArray) && $PHPDateArray['error_count'] == 0) { if (Helpers::dateParseSucceeded($PHPDateArray)) {
// Execute function // Execute function
Helpers::replaceIfEmpty($PHPDateArray['year'], $dti->format('Y')); Helpers::replaceIfEmpty($PHPDateArray['year'], $dti->format('Y'));
if ($PHPDateArray['year'] < $baseYear) { if ($PHPDateArray['year'] < $baseYear) {

View File

@ -282,4 +282,25 @@ class Helpers
$PHPDateObject->modify($mod); $PHPDateObject->modify($mod);
} }
} }
public static function dateParse(string $string): array
{
return self::forceArray(date_parse($string));
}
public static function dateParseSucceeded(array $dateArray): bool
{
return $dateArray['error_count'] === 0;
}
/**
* Despite documentation, date_parse probably never returns false.
* Just in case, this routine helps guarantee it.
*
* @param array|false $dateArray
*/
private static function forceArray($dateArray): array
{
return is_array($dateArray) ? $dateArray : ['error_count' => 1];
}
} }

View File

@ -40,11 +40,17 @@ class TimeValue
$timeValue = implode(':', $arraySplit); $timeValue = implode(':', $arraySplit);
} }
$PHPDateArray = date_parse($timeValue); $PHPDateArray = Helpers::dateParse($timeValue);
$retValue = Functions::VALUE(); $retValue = Functions::VALUE();
if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) { if (Helpers::dateParseSucceeded($PHPDateArray)) {
/** @var int */
$hour = $PHPDateArray['hour'];
/** @var int */
$minute = $PHPDateArray['minute'];
/** @var int */
$second = $PHPDateArray['second'];
// OpenOffice-specific code removed - it works just like Excel // OpenOffice-specific code removed - it works just like Excel
$excelDateValue = SharedDateHelper::formattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1; $excelDateValue = SharedDateHelper::formattedPHPToExcel(1900, 1, 1, $hour, $minute, $second) - 1;
$retType = Functions::getReturnDateType(); $retType = Functions::getReturnDateType();
if ($retType === Functions::RETURNDATE_EXCEL) { if ($retType === Functions::RETURNDATE_EXCEL) {

View File

@ -52,8 +52,10 @@ class NumberFormatter
$number = floor($numberFloat / $divisor); $number = floor($numberFloat / $divisor);
$mask = substr_replace($mask, $blockValue, $offset, $size); $mask = substr_replace($mask, $blockValue, $offset, $size);
} }
/** @var string */
$numberString = $number;
if ($number > 0) { if ($number > 0) {
$mask = substr_replace($mask, $number, $offset, 0); $mask = substr_replace($mask, $numberString, $offset, 0);
} }
$result = $mask; $result = $mask;
} }

View File

@ -102,7 +102,7 @@ class MemoryDrawing extends BaseDrawing
$transparent = imagecolortransparent($this->imageResource); $transparent = imagecolortransparent($this->imageResource);
if ($transparent >= 0) { if ($transparent >= 0) {
$rgb = imagecolorsforindex($this->imageResource, $transparent); $rgb = imagecolorsforindex($this->imageResource, $transparent);
if ($rgb === false) { if (empty($rgb)) {
throw new Exception('Could not get image colors'); throw new Exception('Could not get image colors');
} }

View File

@ -2388,7 +2388,7 @@ class Worksheet extends BIFFwriter
for ($i = 0; $i < $width; ++$i) { for ($i = 0; $i < $width; ++$i) {
$color = imagecolorsforindex($image, imagecolorat($image, $i, $j)); $color = imagecolorsforindex($image, imagecolorat($image, $i, $j));
foreach (['red', 'green', 'blue'] as $key) { foreach (['red', 'green', 'blue'] as $key) {
$color[$key] = $color[$key] + round((255 - $color[$key]) * $color['alpha'] / 127); $color[$key] = $color[$key] + (int) round((255 - $color[$key]) * $color['alpha'] / 127);
} }
$data .= chr($color['blue']) . chr($color['green']) . chr($color['red']); $data .= chr($color['blue']) . chr($color['green']) . chr($color['red']);
} }