Prep Work for Phpstan Upgrade (#2728)

Dependabot submitted PRs #2719 and #2720 to upgrade Phpstan. As with most Phpstan upgrades, there are new error messages; this PR is an attempt to fix all 58 of the new problems in order to allow the upgrade to proceed.

Most of these fixes involve the addition of doc-block type annotations, often involving the assignment of the 'objectionable' portion of the statement to a new variable. Some use explicit casting when I am sure that's safe. Some (Reader/Ods) involve defeating result caching by Phpstan.
This commit is contained in:
oleibman 2022-04-10 08:14:05 -07:00 committed by GitHub
parent 28bb2cd7c7
commit 64e61d8dec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 143 additions and 73 deletions

View File

@ -340,11 +340,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php
-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselK\\:\\:besselK2\\(\\) has no return type specified\\.$#"
count: 1
path: src/PhpSpreadsheet/Calculation/Engineering/BesselK.php
- -
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertBase\\:\\:validatePlaces\\(\\) has parameter \\$places with no type specified\\.$#" message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertBase\\:\\:validatePlaces\\(\\) has parameter \\$places with no type specified\\.$#"
count: 1 count: 1
@ -2070,11 +2065,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Reader/Ods.php path: src/PhpSpreadsheet/Reader/Ods.php
-
message: "#^If condition is always true\\.$#"
count: 1
path: src/PhpSpreadsheet/Reader/Ods.php
- -
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:listWorksheetNames\\(\\) should return array\\<string\\> but returns array\\<int, string\\|null\\>\\.$#" message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:listWorksheetNames\\(\\) should return array\\<string\\> but returns array\\<int, string\\|null\\>\\.$#"
count: 1 count: 1
@ -2095,11 +2085,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Reader/Ods.php path: src/PhpSpreadsheet/Reader/Ods.php
-
message: "#^While loop condition is always true\\.$#"
count: 2
path: src/PhpSpreadsheet/Reader/Ods.php
- -
message: "#^Cannot call method getElementsByTagNameNS\\(\\) on DOMElement\\|null\\.$#" message: "#^Cannot call method getElementsByTagNameNS\\(\\) on DOMElement\\|null\\.$#"
count: 3 count: 3
@ -3880,11 +3865,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Shared/Trend/Trend.php path: src/PhpSpreadsheet/Shared/Trend/Trend.php
-
message: "#^Parameter \\#1 \\$order of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\PolynomialBestFit constructor expects int, string given\\.$#"
count: 2
path: src/PhpSpreadsheet/Shared/Trend/Trend.php
- -
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\XMLWriter\\:\\:getData\\(\\) should return string but returns string\\|false\\.$#" message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\XMLWriter\\:\\:getData\\(\\) should return string but returns string\\|false\\.$#"
count: 1 count: 1

View File

@ -68,13 +68,28 @@ class BesselK
return self::besselK2($x, $ord); return self::besselK2($x, $ord);
} }
/**
* Mollify Phpstan.
*
* @codeCoverageIgnore
*/
private static function callBesselI(float $x, int $ord): float
{
$rslt = BesselI::BESSELI($x, $ord);
if (!is_float($rslt)) {
throw new Exception('Unexpected array or string');
}
return $rslt;
}
private static function besselK0(float $x): float private static function besselK0(float $x): float
{ {
if ($x <= 2) { if ($x <= 2) {
$fNum2 = $x * 0.5; $fNum2 = $x * 0.5;
$y = ($fNum2 * $fNum2); $y = ($fNum2 * $fNum2);
return -log($fNum2) * BesselI::BESSELI($x, 0) + return -log($fNum2) * self::callBesselI($x, 0) +
(-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y * (-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y *
(0.10750e-3 + $y * 0.74e-5)))))); (0.10750e-3 + $y * 0.74e-5))))));
} }
@ -92,7 +107,7 @@ class BesselK
$fNum2 = $x * 0.5; $fNum2 = $x * 0.5;
$y = ($fNum2 * $fNum2); $y = ($fNum2 * $fNum2);
return log($fNum2) * BesselI::BESSELI($x, 1) + return log($fNum2) * self::callBesselI($x, 1) +
(1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y * (1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y *
(-0.110404e-2 + $y * (-0.4686e-4))))))) / $x; (-0.110404e-2 + $y * (-0.4686e-4))))))) / $x;
} }
@ -104,7 +119,7 @@ class BesselK
(0.325614e-2 + $y * (-0.68245e-3))))))); (0.325614e-2 + $y * (-0.68245e-3)))))));
} }
private static function besselK2(float $x, int $ord) private static function besselK2(float $x, int $ord): float
{ {
$fTox = 2 / $x; $fTox = 2 / $x;
$fBkm = self::besselK0($x); $fBkm = self::besselK0($x);

View File

@ -66,6 +66,21 @@ class BesselY
return self::besselY2($x, $ord); return self::besselY2($x, $ord);
} }
/**
* Mollify Phpstan.
*
* @codeCoverageIgnore
*/
private static function callBesselJ(float $x, int $ord): float
{
$rslt = BesselJ::BESSELJ($x, $ord);
if (!is_float($rslt)) {
throw new Exception('Unexpected array or string');
}
return $rslt;
}
private static function besselY0(float $x): float private static function besselY0(float $x): float
{ {
if ($x < 8.0) { if ($x < 8.0) {
@ -75,7 +90,7 @@ class BesselY
$ans2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * $ans2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y *
(47447.26470 + $y * (226.1030244 + $y)))); (47447.26470 + $y * (226.1030244 + $y))));
return $ans1 / $ans2 + 0.636619772 * BesselJ::BESSELJ($x, 0) * log($x); return $ans1 / $ans2 + 0.636619772 * self::callBesselJ($x, 0) * log($x);
} }
$z = 8.0 / $x; $z = 8.0 / $x;
@ -97,7 +112,7 @@ class BesselY
$ans2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y * $ans2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y *
(0.1020426050e6 + $y * (0.3549632885e3 + $y))))); (0.1020426050e6 + $y * (0.3549632885e3 + $y)))));
return ($ans1 / $ans2) + 0.636619772 * (BesselJ::BESSELJ($x, 1) * log($x) - 1 / $x); return ($ans1 / $ans2) + 0.636619772 * (self::callBesselJ($x, 1) * log($x) - 1 / $x);
} }
$z = 8.0 / $x; $z = 8.0 / $x;

View File

@ -70,10 +70,12 @@ class Amortization
return $e->getMessage(); return $e->getMessage();
} }
$yearFrac = DateTimeExcel\YearFrac::fraction($purchased, $firstPeriod, $basis); $yearFracx = DateTimeExcel\YearFrac::fraction($purchased, $firstPeriod, $basis);
if (is_string($yearFrac)) { if (is_string($yearFracx)) {
return $yearFrac; return $yearFracx;
} }
/** @var float */
$yearFrac = $yearFracx;
$amortiseCoeff = self::getAmortizationCoefficient($rate); $amortiseCoeff = self::getAmortizationCoefficient($rate);
@ -161,10 +163,12 @@ class Amortization
$fCostDelta = $cost - $salvage; $fCostDelta = $cost - $salvage;
// Note, quirky variation for leap years on the YEARFRAC for this function // Note, quirky variation for leap years on the YEARFRAC for this function
$purchasedYear = DateTimeExcel\DateParts::year($purchased); $purchasedYear = DateTimeExcel\DateParts::year($purchased);
$yearFrac = DateTimeExcel\YearFrac::fraction($purchased, $firstPeriod, $basis); $yearFracx = DateTimeExcel\YearFrac::fraction($purchased, $firstPeriod, $basis);
if (is_string($yearFrac)) { if (is_string($yearFracx)) {
return $yearFrac; return $yearFracx;
} }
/** @var float */
$yearFrac = $yearFracx;
if ( if (
($basis == FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL) && ($basis == FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL) &&

View File

@ -199,6 +199,7 @@ class Coupons
return $e->getMessage(); return $e->getMessage();
} }
/** @var int */
$daysPerYear = Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis); $daysPerYear = Helpers::daysPerYear(DateTimeExcel\DateParts::year($settlement), $basis);
$next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_NEXT); $next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_NEXT);

View File

@ -44,7 +44,9 @@ class Confidence
if (($alpha <= 0) || ($alpha >= 1) || ($stdDev <= 0) || ($size < 1)) { if (($alpha <= 0) || ($alpha >= 1) || ($stdDev <= 0) || ($size < 1)) {
return ExcelError::NAN(); return ExcelError::NAN();
} }
/** @var float */
$temp = Distributions\StandardNormal::inverse(1 - $alpha / 2);
return Functions::scalar(Distributions\StandardNormal::inverse(1 - $alpha / 2) * $stdDev / sqrt($size)); return Functions::scalar($temp * $stdDev / sqrt($size));
} }
} }

View File

@ -56,8 +56,10 @@ class Binomial
if ($cumulative) { if ($cumulative) {
return self::calculateCumulativeBinomial($value, $trials, $probability); return self::calculateCumulativeBinomial($value, $trials, $probability);
} }
/** @var float */
$comb = Combinations::withoutRepetition($trials, $value);
return Combinations::withoutRepetition($trials, $value) * $probability ** $value return $comb * $probability ** $value
* (1 - $probability) ** ($trials - $value); * (1 - $probability) ** ($trials - $value);
} }
@ -107,7 +109,9 @@ class Binomial
$summer = 0; $summer = 0;
for ($i = $successes; $i <= $limit; ++$i) { for ($i = $successes; $i <= $limit; ++$i) {
$summer += Combinations::withoutRepetition($trials, $i) * $probability ** $i /** @var float */
$comb = Combinations::withoutRepetition($trials, $i);
$summer += $comb * $probability ** $i
* (1 - $probability) ** ($trials - $i); * (1 - $probability) ** ($trials - $i);
} }
@ -159,8 +163,10 @@ class Binomial
return ExcelError::NAN(); return ExcelError::NAN();
} }
} }
/** @var float */
$comb = Combinations::withoutRepetition($failures + $successes - 1, $successes - 1);
return (Combinations::withoutRepetition($failures + $successes - 1, $successes - 1)) return $comb
* ($probability ** $successes) * ((1 - $probability) ** $failures); * ($probability ** $successes) * ((1 - $probability) ** $failures);
} }
@ -220,7 +226,9 @@ class Binomial
{ {
$summer = 0; $summer = 0;
for ($i = 0; $i <= $value; ++$i) { for ($i = 0; $i <= $value; ++$i) {
$summer += Combinations::withoutRepetition($trials, $i) * $probability ** $i /** @var float */
$comb = Combinations::withoutRepetition($trials, $i);
$summer += $comb * $probability ** $i
* (1 - $probability) ** ($trials - $i); * (1 - $probability) ** ($trials - $i);
} }

View File

@ -281,6 +281,7 @@ class ChiSquared
// Relative error controlled by the eps parameter // Relative error controlled by the eps parameter
private static function gser($n, $x) private static function gser($n, $x)
{ {
/** @var float */
$gln = Gamma::ln($n / 2); $gln = Gamma::ln($n / 2);
$a = 0.5 * $n; $a = 0.5 * $n;
$ap = $a; $ap = $a;
@ -304,6 +305,7 @@ class ChiSquared
// Relative error controlled by the eps parameter // Relative error controlled by the eps parameter
private static function gcf($n, $x) private static function gcf($n, $x)
{ {
/** @var float */
$gln = Gamma::ln($n / 2); $gln = Gamma::ln($n / 2);
$a = 0.5 * $n; $a = 0.5 * $n;
$b = $x + 1 - $a; $b = $x + 1 - $a;

View File

@ -131,7 +131,9 @@ class LogNormal
if ($stdDev <= 0) { if ($stdDev <= 0) {
return ExcelError::NAN(); return ExcelError::NAN();
} }
/** @var float */
$inverse = StandardNormal::inverse($probability);
return exp($mean + $stdDev * StandardNormal::inverse($probability)); return exp($mean + $stdDev * $inverse);
} }
} }

View File

@ -51,12 +51,16 @@ class Poisson
$summer = 0; $summer = 0;
$floor = floor($value); $floor = floor($value);
for ($i = 0; $i <= $floor; ++$i) { for ($i = 0; $i <= $floor; ++$i) {
$summer += $mean ** $i / MathTrig\Factorial::fact($i); /** @var float */
$fact = MathTrig\Factorial::fact($i);
$summer += $mean ** $i / $fact;
} }
return exp(0 - $mean) * $summer; return exp(0 - $mean) * $summer;
} }
/** @var float */
$fact = MathTrig\Factorial::fact($value);
return (exp(0 - $mean) * $mean ** $value) / MathTrig\Factorial::fact($value); return (exp(0 - $mean) * $mean ** $value) / $fact;
} }
} }

View File

@ -103,8 +103,10 @@ class StandardNormal
if (!is_numeric($value)) { if (!is_numeric($value)) {
return ExcelError::VALUE(); return ExcelError::VALUE();
} }
/** @var float */
$dist = self::distribution($value, true);
return self::distribution($value, true) - 0.5; return $dist - 0.5;
} }
/** /**
@ -139,6 +141,7 @@ class StandardNormal
} }
if ($sigma === null) { if ($sigma === null) {
/** @var float */
$sigma = StandardDeviations::STDEV($dataSet); $sigma = StandardDeviations::STDEV($dataSet);
} }
$n = count($dataSet); $n = count($dataSet);

View File

@ -31,7 +31,7 @@ class Size
$mArgs = self::filter($aArgs); $mArgs = self::filter($aArgs);
$count = Counts::COUNT($mArgs); $count = Counts::COUNT($mArgs);
--$entry; --$entry;
if (($entry < 0) || ($entry >= $count) || ($count == 0)) { if ($count === 0 || $entry < 0 || $entry >= $count) {
return ExcelError::NAN(); return ExcelError::NAN();
} }
rsort($mArgs); rsort($mArgs);
@ -67,7 +67,7 @@ class Size
$mArgs = self::filter($aArgs); $mArgs = self::filter($aArgs);
$count = Counts::COUNT($mArgs); $count = Counts::COUNT($mArgs);
--$entry; --$entry;
if (($entry < 0) || ($entry >= $count) || ($count == 0)) { if ($count === 0 || $entry < 0 || $entry >= $count) {
return ExcelError::NAN(); return ExcelError::NAN();
} }
sort($mArgs); sort($mArgs);

View File

@ -179,6 +179,8 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder
{ {
// Convert value to number // Convert value to number
[$hours, $minutes] = explode(':', $value); [$hours, $minutes] = explode(':', $value);
$hours = (int) $hours;
$minutes = (int) $minutes;
$days = ($hours / 24) + ($minutes / 1440); $days = ($hours / 24) + ($minutes / 1440);
$cell->setValueExplicit($days, DataType::TYPE_NUMERIC); $cell->setValueExplicit($days, DataType::TYPE_NUMERIC);
@ -193,6 +195,9 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder
{ {
// Convert value to number // Convert value to number
[$hours, $minutes, $seconds] = explode(':', $value); [$hours, $minutes, $seconds] = explode(':', $value);
$hours = (int) $hours;
$minutes = (int) $minutes;
$seconds = (int) $seconds;
$days = ($hours / 24) + ($minutes / 1440) + ($seconds / 86400); $days = ($hours / 24) + ($minutes / 1440) + ($seconds / 86400);
$cell->setValueExplicit($days, DataType::TYPE_NUMERIC); $cell->setValueExplicit($days, DataType::TYPE_NUMERIC);

View File

@ -105,7 +105,7 @@ class Ods extends BaseReader
$xml->read(); $xml->read();
while ($xml->read()) { while ($xml->read()) {
// Quickly jump through to the office:body node // Quickly jump through to the office:body node
while ($xml->name !== 'office:body') { while (self::getXmlName($xml) !== 'office:body') {
if ($xml->isEmptyElement) { if ($xml->isEmptyElement) {
$xml->read(); $xml->read();
} else { } else {
@ -114,12 +114,13 @@ class Ods extends BaseReader
} }
// Now read each node until we find our first table:table node // Now read each node until we find our first table:table node
while ($xml->read()) { while ($xml->read()) {
if ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) { $xmlName = self::getXmlName($xml);
if ($xmlName == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) {
// Loop through each table:table node reading the table:name attribute for each worksheet name // Loop through each table:table node reading the table:name attribute for each worksheet name
do { do {
$worksheetNames[] = $xml->getAttribute('table:name'); $worksheetNames[] = $xml->getAttribute('table:name');
$xml->next(); $xml->next();
} while ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT); } while (self::getXmlName($xml) == 'table:table' && $xml->nodeType == XMLReader::ELEMENT);
} }
} }
} }
@ -152,7 +153,7 @@ class Ods extends BaseReader
$xml->read(); $xml->read();
while ($xml->read()) { while ($xml->read()) {
// Quickly jump through to the office:body node // Quickly jump through to the office:body node
while ($xml->name !== 'office:body') { while (self::getXmlName($xml) !== 'office:body') {
if ($xml->isEmptyElement) { if ($xml->isEmptyElement) {
$xml->read(); $xml->read();
} else { } else {
@ -161,7 +162,7 @@ class Ods extends BaseReader
} }
// Now read each node until we find our first table:table node // Now read each node until we find our first table:table node
while ($xml->read()) { while ($xml->read()) {
if ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) { if (self::getXmlName($xml) == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) {
$worksheetNames[] = $xml->getAttribute('table:name'); $worksheetNames[] = $xml->getAttribute('table:name');
$tmpInfo = [ $tmpInfo = [
@ -176,7 +177,7 @@ class Ods extends BaseReader
$currCells = 0; $currCells = 0;
do { do {
$xml->read(); $xml->read();
if ($xml->name == 'table:table-row' && $xml->nodeType == XMLReader::ELEMENT) { if (self::getXmlName($xml) == 'table:table-row' && $xml->nodeType == XMLReader::ELEMENT) {
$rowspan = $xml->getAttribute('table:number-rows-repeated'); $rowspan = $xml->getAttribute('table:number-rows-repeated');
$rowspan = empty($rowspan) ? 1 : $rowspan; $rowspan = empty($rowspan) ? 1 : $rowspan;
$tmpInfo['totalRows'] += $rowspan; $tmpInfo['totalRows'] += $rowspan;
@ -186,22 +187,22 @@ class Ods extends BaseReader
$xml->read(); $xml->read();
do { do {
$doread = true; $doread = true;
if ($xml->name == 'table:table-cell' && $xml->nodeType == XMLReader::ELEMENT) { if (self::getXmlName($xml) == 'table:table-cell' && $xml->nodeType == XMLReader::ELEMENT) {
if (!$xml->isEmptyElement) { if (!$xml->isEmptyElement) {
++$currCells; ++$currCells;
$xml->next(); $xml->next();
$doread = false; $doread = false;
} }
} elseif ($xml->name == 'table:covered-table-cell' && $xml->nodeType == XMLReader::ELEMENT) { } elseif (self::getXmlName($xml) == 'table:covered-table-cell' && $xml->nodeType == XMLReader::ELEMENT) {
$mergeSize = $xml->getAttribute('table:number-columns-repeated'); $mergeSize = $xml->getAttribute('table:number-columns-repeated');
$currCells += (int) $mergeSize; $currCells += (int) $mergeSize;
} }
if ($doread) { if ($doread) {
$xml->read(); $xml->read();
} }
} while ($xml->name != 'table:table-row'); } while (self::getXmlName($xml) != 'table:table-row');
} }
} while ($xml->name != 'table:table'); } while (self::getXmlName($xml) != 'table:table');
$tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells); $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
$tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1; $tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1;
@ -214,6 +215,16 @@ class Ods extends BaseReader
return $worksheetInfo; return $worksheetInfo;
} }
/**
* Counteract Phpstan caching.
*
* @phpstan-impure
*/
private static function getXmlName(XMLReader $xml): string
{
return $xml->name;
}
/** /**
* Loads PhpSpreadsheet from file. * Loads PhpSpreadsheet from file.
*/ */
@ -681,12 +692,7 @@ class Ods extends BaseReader
// Multiple spaces? // Multiple spaces?
/** @var DOMAttr $cAttr */ /** @var DOMAttr $cAttr */
$cAttr = $child->attributes->getNamedItem('c'); $cAttr = $child->attributes->getNamedItem('c');
if ($cAttr) { $multiplier = self::getMultiplier($cAttr);
$multiplier = (int) $cAttr->nodeValue;
} else {
$multiplier = 1;
}
$str .= str_repeat(' ', $multiplier); $str .= str_repeat(' ', $multiplier);
} }
@ -698,6 +704,17 @@ class Ods extends BaseReader
return $str; return $str;
} }
private static function getMultiplier(?DOMAttr $cAttr): int
{
if ($cAttr) {
$multiplier = (int) $cAttr->nodeValue;
} else {
$multiplier = 1;
}
return $multiplier;
}
/** /**
* @param string $is * @param string $is
* *

View File

@ -894,7 +894,7 @@ class Xlsx extends BaseReader
} }
foreach ($xmlSheet->extLst->ext->children('x14', true)->dataValidations->dataValidation as $item) { foreach ($xmlSheet->extLst->ext->children('x14', true)->dataValidations->dataValidation as $item) {
$node = $xmlSheet->dataValidations->addChild('dataValidation'); $node = self::testSimpleXml($xmlSheet->dataValidations)->addChild('dataValidation');
foreach ($item->attributes() ?? [] as $attr) { foreach ($item->attributes() ?? [] as $attr) {
$node->addAttribute($attr->getName(), $attr); $node->addAttribute($attr->getName(), $attr);
} }

View File

@ -83,7 +83,7 @@ class Trend
case self::TREND_POLYNOMIAL_5: case self::TREND_POLYNOMIAL_5:
case self::TREND_POLYNOMIAL_6: case self::TREND_POLYNOMIAL_6:
if (!isset(self::$trendCache[$key])) { if (!isset(self::$trendCache[$key])) {
$order = substr($trendType, -1); $order = (int) substr($trendType, -1);
self::$trendCache[$key] = new PolynomialBestFit($order, $yValues, $xValues); self::$trendCache[$key] = new PolynomialBestFit($order, $yValues, $xValues);
} }
@ -101,7 +101,7 @@ class Trend
} }
if ($trendType != self::TREND_BEST_FIT_NO_POLY) { if ($trendType != self::TREND_BEST_FIT_NO_POLY) {
foreach (self::$trendTypePolynomialOrders as $trendMethod) { foreach (self::$trendTypePolynomialOrders as $trendMethod) {
$order = substr($trendMethod, -1); $order = (int) substr($trendMethod, -1);
$bestFit[$trendMethod] = new PolynomialBestFit($order, $yValues, $xValues); $bestFit[$trendMethod] = new PolynomialBestFit($order, $yValues, $xValues);
if ($bestFit[$trendMethod]->getError()) { if ($bestFit[$trendMethod]->getError()) {
unset($bestFit[$trendMethod]); unset($bestFit[$trendMethod]);

View File

@ -293,7 +293,10 @@ class Color extends Supervisor
*/ */
private static function getColourComponent($rgbValue, $offset, $hex = true) private static function getColourComponent($rgbValue, $offset, $hex = true)
{ {
$colour = substr($rgbValue, $offset, 2); $colour = substr($rgbValue, $offset, 2) ?: '';
if (preg_match('/^[0-9a-f]{2}$/i', $colour) !== 1) {
$colour = '00';
}
return ($hex) ? $colour : (int) hexdec($colour); return ($hex) ? $colour : (int) hexdec($colour);
} }

View File

@ -26,9 +26,12 @@ class FractionFormatter extends BaseFormatter
$decimalLength = strlen($decimalPart); $decimalLength = strlen($decimalPart);
$decimalDivisor = 10 ** $decimalLength; $decimalDivisor = 10 ** $decimalLength;
/** @var float */
$GCD = MathTrig\Gcd::evaluate($decimalPart, $decimalDivisor); $GCD = MathTrig\Gcd::evaluate($decimalPart, $decimalDivisor);
/** @var float */
$decimalPartx = $decimalPart;
$adjustedDecimalPart = $decimalPart / $GCD; $adjustedDecimalPart = $decimalPartx / $GCD;
$adjustedDecimalDivisor = $decimalDivisor / $GCD; $adjustedDecimalDivisor = $decimalDivisor / $GCD;
if ((strpos($format, '0') !== false)) { if ((strpos($format, '0') !== false)) {

View File

@ -54,6 +54,12 @@ use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
// */ // */
class Worksheet extends BIFFwriter class Worksheet extends BIFFwriter
{ {
/** @var int */
private static $always0 = 0;
/** @var int */
private static $always1 = 1;
/** /**
* Formula parser. * Formula parser.
* *
@ -2923,11 +2929,11 @@ class Worksheet extends BIFFwriter
$flags |= (1 == $bAlignWrapTx ? 0x00000004 : 0); $flags |= (1 == $bAlignWrapTx ? 0x00000004 : 0);
$flags |= (1 == $bTxRotation ? 0x00000008 : 0); $flags |= (1 == $bTxRotation ? 0x00000008 : 0);
// Justify last line flag // Justify last line flag
$flags |= (1 == 1 ? 0x00000010 : 0); $flags |= (1 == self::$always1 ? 0x00000010 : 0);
$flags |= (1 == $bIndent ? 0x00000020 : 0); $flags |= (1 == $bIndent ? 0x00000020 : 0);
$flags |= (1 == $bShrinkToFit ? 0x00000040 : 0); $flags |= (1 == $bShrinkToFit ? 0x00000040 : 0);
// Default // Default
$flags |= (1 == 1 ? 0x00000080 : 0); $flags |= (1 == self::$always1 ? 0x00000080 : 0);
// Protection // Protection
$flags |= (1 == $bProtLocked ? 0x00000100 : 0); $flags |= (1 == $bProtLocked ? 0x00000100 : 0);
$flags |= (1 == $bProtHidden ? 0x00000200 : 0); $flags |= (1 == $bProtHidden ? 0x00000200 : 0);
@ -2936,13 +2942,13 @@ class Worksheet extends BIFFwriter
$flags |= (1 == $bBorderRight ? 0x00000800 : 0); $flags |= (1 == $bBorderRight ? 0x00000800 : 0);
$flags |= (1 == $bBorderTop ? 0x00001000 : 0); $flags |= (1 == $bBorderTop ? 0x00001000 : 0);
$flags |= (1 == $bBorderBottom ? 0x00002000 : 0); $flags |= (1 == $bBorderBottom ? 0x00002000 : 0);
$flags |= (1 == 1 ? 0x00004000 : 0); // Top left to Bottom right border $flags |= (1 == self::$always1 ? 0x00004000 : 0); // Top left to Bottom right border
$flags |= (1 == 1 ? 0x00008000 : 0); // Bottom left to Top right border $flags |= (1 == self::$always1 ? 0x00008000 : 0); // Bottom left to Top right border
// Pattern // Pattern
$flags |= (1 == $bFillStyle ? 0x00010000 : 0); $flags |= (1 == $bFillStyle ? 0x00010000 : 0);
$flags |= (1 == $bFillColor ? 0x00020000 : 0); $flags |= (1 == $bFillColor ? 0x00020000 : 0);
$flags |= (1 == $bFillColorBg ? 0x00040000 : 0); $flags |= (1 == $bFillColorBg ? 0x00040000 : 0);
$flags |= (1 == 1 ? 0x00380000 : 0); $flags |= (1 == self::$always1 ? 0x00380000 : 0);
// Font // Font
$flags |= (1 == $bFormatFont ? 0x04000000 : 0); $flags |= (1 == $bFormatFont ? 0x04000000 : 0);
// Alignment: // Alignment:
@ -2954,7 +2960,7 @@ class Worksheet extends BIFFwriter
// Protection // Protection
$flags |= (1 == $bFormatProt ? 0x40000000 : 0); $flags |= (1 == $bFormatProt ? 0x40000000 : 0);
// Text direction // Text direction
$flags |= (1 == 0 ? 0x80000000 : 0); $flags |= (1 == self::$always0 ? 0x80000000 : 0);
$dataBlockFont = null; $dataBlockFont = null;
$dataBlockAlign = null; $dataBlockAlign = null;
@ -3040,10 +3046,10 @@ class Worksheet extends BIFFwriter
$optionsFlags = 0; $optionsFlags = 0;
$optionsFlagsBold = ($conditional->getStyle()->getFont()->getBold() === null ? 1 : 0); $optionsFlagsBold = ($conditional->getStyle()->getFont()->getBold() === null ? 1 : 0);
$optionsFlags |= (1 == $optionsFlagsBold ? 0x00000002 : 0); $optionsFlags |= (1 == $optionsFlagsBold ? 0x00000002 : 0);
$optionsFlags |= (1 == 1 ? 0x00000008 : 0); $optionsFlags |= (1 == self::$always1 ? 0x00000008 : 0);
$optionsFlags |= (1 == 1 ? 0x00000010 : 0); $optionsFlags |= (1 == self::$always1 ? 0x00000010 : 0);
$optionsFlags |= (1 == 0 ? 0x00000020 : 0); $optionsFlags |= (1 == self::$always0 ? 0x00000020 : 0);
$optionsFlags |= (1 == 1 ? 0x00000080 : 0); $optionsFlags |= (1 == self::$always1 ? 0x00000080 : 0);
$dataBlockFont .= pack('V', $optionsFlags); $dataBlockFont .= pack('V', $optionsFlags);
// Escapement type // Escapement type
$dataBlockFont .= pack('V', $fontEscapement); $dataBlockFont .= pack('V', $fontEscapement);