Skip to content

Commit cabd60c

Browse files
authored
Merge pull request #4060 from oleibman/stan9d
Better Definitions for Mixed Parameters and Values Part 3 of Many
2 parents 275b948 + 85c1512 commit cabd60c

15 files changed

+125
-55
lines changed

src/PhpSpreadsheet/Calculation/Calculation.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class Calculation
120120
*/
121121
private Logger $debugLog;
122122

123-
private bool $suppressFormulaErrorsNew = false;
123+
private bool $suppressFormulaErrors = false;
124124

125125
/**
126126
* Error message for any error that was raised/thrown by the calculation engine.
@@ -5350,7 +5350,7 @@ protected function raiseFormulaError(string $errorMessage, int $code = 0, ?Throw
53505350
{
53515351
$this->formulaError = $errorMessage;
53525352
$this->cyclicReferenceStack->clear();
5353-
$suppress = $this->suppressFormulaErrors ?? $this->suppressFormulaErrorsNew;
5353+
$suppress = $this->suppressFormulaErrors;
53545354
if (!$suppress) {
53555355
throw new Exception($errorMessage, $code, $exception);
53565356
}
@@ -5634,12 +5634,12 @@ private function evaluateDefinedName(Cell $cell, DefinedName $namedRange, Worksh
56345634

56355635
public function setSuppressFormulaErrors(bool $suppressFormulaErrors): void
56365636
{
5637-
$this->suppressFormulaErrorsNew = $suppressFormulaErrors;
5637+
$this->suppressFormulaErrors = $suppressFormulaErrors;
56385638
}
56395639

56405640
public function getSuppressFormulaErrors(): bool
56415641
{
5642-
return $this->suppressFormulaErrorsNew;
5642+
return $this->suppressFormulaErrors;
56435643
}
56445644

56455645
private static function boolToString(mixed $operand1): mixed

src/PhpSpreadsheet/Cell/AdvancedValueBinder.php

+5-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
66
use PhpOffice\PhpSpreadsheet\Calculation\Engine\FormattedNumber;
7-
use PhpOffice\PhpSpreadsheet\RichText\RichText;
87
use PhpOffice\PhpSpreadsheet\Shared\Date;
98
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
109
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
@@ -30,7 +29,7 @@ public function bindValue(Cell $cell, mixed $value = null): bool
3029
$dataType = parent::dataTypeForValue($value);
3130

3231
// Style logic - strings
33-
if ($dataType === DataType::TYPE_STRING && !$value instanceof RichText) {
32+
if ($dataType === DataType::TYPE_STRING && is_string($value)) {
3433
// Test for booleans using locale-setting
3534
if (StringHelper::strToUpper($value) === Calculation::getTRUE()) {
3635
$cell->setValueExplicit(true, DataType::TYPE_BOOL);
@@ -54,17 +53,17 @@ public function bindValue(Cell $cell, mixed $value = null): bool
5453
$thousandsSeparator = preg_quote(StringHelper::getThousandsSeparator(), '/');
5554

5655
// Check for percentage
57-
if (preg_match('/^\-?\d*' . $decimalSeparator . '?\d*\s?\%$/', preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value))) {
58-
return $this->setPercentage(preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value), $cell);
56+
if (preg_match('/^\-?\d*' . $decimalSeparator . '?\d*\s?\%$/', (string) preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value))) {
57+
return $this->setPercentage((string) preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value), $cell);
5958
}
6059

6160
// Check for currency
62-
if (preg_match(FormattedNumber::currencyMatcherRegexp(), preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value), $matches, PREG_UNMATCHED_AS_NULL)) {
61+
if (preg_match(FormattedNumber::currencyMatcherRegexp(), (string) preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value), $matches, PREG_UNMATCHED_AS_NULL)) {
6362
// Convert value to number
6463
$sign = ($matches['PrefixedSign'] ?? $matches['PrefixedSign2'] ?? $matches['PostfixedSign']) ?? null;
6564
$currencyCode = $matches['PrefixedCurrency'] ?? $matches['PostfixedCurrency'];
6665
/** @var string */
67-
$temp = str_replace([$decimalSeparatorNoPreg, $currencyCode, ' ', '-'], ['.', '', '', ''], preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value));
66+
$temp = str_replace([$decimalSeparatorNoPreg, $currencyCode, ' ', '-'], ['.', '', '', ''], (string) preg_replace('/(\d)' . $thousandsSeparator . '(\d)/u', '$1$2', $value));
6867
$value = (float) ($sign . trim($temp));
6968

7069
return $this->setCurrency($value, $cell, $currencyCode ?? '');

src/PhpSpreadsheet/Cell/Cell.php

+13-3
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,15 @@ public function getValueString(): string
188188
public function getFormattedValue(): string
189189
{
190190
return (string) NumberFormat::toFormattedString(
191-
$this->getCalculatedValue(),
191+
$this->getCalculatedValueString(),
192192
(string) $this->getStyle()->getNumberFormat()->getFormatCode(true)
193193
);
194194
}
195195

196196
protected static function updateIfCellIsTableHeader(?Worksheet $workSheet, self $cell, mixed $oldValue, mixed $newValue): void
197197
{
198+
$oldValue = (is_scalar($oldValue) || $oldValue instanceof Stringable) ? ((string) $oldValue) : null;
199+
$newValue = (is_scalar($newValue) || $newValue instanceof Stringable) ? ((string) $newValue) : null;
198200
if (StringHelper::strToLower($oldValue ?? '') === StringHelper::strToLower($newValue ?? '') || $workSheet === null) {
199201
return;
200202
}
@@ -262,7 +264,10 @@ public function setValueExplicit(mixed $value, string $dataType = DataType::TYPE
262264
// Synonym for string
263265
case DataType::TYPE_INLINE:
264266
// Rich text
265-
$this->value = DataType::checkString($value);
267+
if ($value !== null && !is_scalar($value) && !($value instanceof Stringable)) {
268+
throw new SpreadsheetException('Invalid unstringable value for datatype Inline/String/String2');
269+
}
270+
$this->value = DataType::checkString(($value instanceof RichText) ? $value : ((string) $value));
266271

267272
break;
268273
case DataType::TYPE_NUMERIC:
@@ -273,6 +278,9 @@ public function setValueExplicit(mixed $value, string $dataType = DataType::TYPE
273278

274279
break;
275280
case DataType::TYPE_FORMULA:
281+
if ($value !== null && !is_scalar($value) && !($value instanceof Stringable)) {
282+
throw new SpreadsheetException('Invalid unstringable value for datatype Formula');
283+
}
276284
$this->value = (string) $value;
277285

278286
break;
@@ -790,7 +798,9 @@ public function getFormulaAttributes(): mixed
790798
*/
791799
public function __toString(): string
792800
{
793-
return (string) $this->getValue();
801+
$retVal = $this->value;
802+
803+
return ($retVal === null || is_scalar($retVal) || $retVal instanceof Stringable) ? ((string) $retVal) : '';
794804
}
795805

796806
public function getIgnoredErrors(): IgnoredErrors

src/PhpSpreadsheet/Cell/DataType.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PhpOffice\PhpSpreadsheet\RichText\RichText;
66
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
7+
use Stringable;
78

89
class DataType
910
{
@@ -78,7 +79,7 @@ public static function checkString(null|RichText|string $textValue): RichText|st
7879
*/
7980
public static function checkErrorCode(mixed $value): string
8081
{
81-
$value = (string) $value;
82+
$value = (is_scalar($value) || $value instanceof Stringable) ? ((string) $value) : '#NULL!';
8283

8384
if (!isset(self::$errorCodes[$value])) {
8485
$value = '#NULL!';

src/PhpSpreadsheet/Cell/DataValidator.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function isValid(Cell $cell): bool
4646
$returnValue = $this->numericOperator($dataValidation, (float) $cellValue);
4747
}
4848
} elseif ($type === DataValidation::TYPE_TEXTLENGTH) {
49-
$returnValue = $this->numericOperator($dataValidation, mb_strlen((string) $cellValue));
49+
$returnValue = $this->numericOperator($dataValidation, mb_strlen($cell->getValueString()));
5050
}
5151

5252
return $returnValue;
@@ -86,14 +86,14 @@ private function numericOperator(DataValidation $dataValidation, int|float $cell
8686
*/
8787
private function isValueInList(Cell $cell): bool
8888
{
89-
$cellValue = $cell->getValue();
89+
$cellValueString = $cell->getValueString();
9090
$dataValidation = $cell->getDataValidation();
9191

9292
$formula1 = $dataValidation->getFormula1();
9393
if (!empty($formula1)) {
9494
// inline values list
9595
if ($formula1[0] === '"') {
96-
return in_array(strtolower($cellValue), explode(',', strtolower(trim($formula1, '"'))), true);
96+
return in_array(strtolower($cellValueString), explode(',', strtolower(trim($formula1, '"'))), true);
9797
} elseif (strpos($formula1, ':') > 0) {
9898
// values list cells
9999
$matchFormula = '=MATCH(' . $cell->getCoordinate() . ', ' . $formula1 . ', 0)';

src/PhpSpreadsheet/Cell/DefaultValueBinder.php

+25-12
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,33 @@ public static function dataTypeForValue(mixed $value): string
4646
// Match the value against a few data types
4747
if ($value === null) {
4848
return DataType::TYPE_NULL;
49-
} elseif (is_float($value) || is_int($value)) {
49+
}
50+
if (is_float($value) || is_int($value)) {
5051
return DataType::TYPE_NUMERIC;
51-
} elseif (is_bool($value)) {
52+
}
53+
if (is_bool($value)) {
5254
return DataType::TYPE_BOOL;
53-
} elseif ($value === '') {
55+
}
56+
if ($value === '') {
5457
return DataType::TYPE_STRING;
55-
} elseif ($value instanceof RichText) {
58+
}
59+
if ($value instanceof RichText) {
5660
return DataType::TYPE_INLINE;
57-
} elseif (is_string($value) && strlen($value) > 1 && $value[0] === '=') {
61+
}
62+
if ($value instanceof Stringable) {
63+
$value = (string) $value;
64+
}
65+
if (!is_string($value)) {
66+
$gettype = is_object($value) ? get_class($value) : gettype($value);
67+
68+
throw new SpreadsheetException("unusable type $gettype");
69+
}
70+
if (strlen($value) > 1 && $value[0] === '=') {
5871
return DataType::TYPE_FORMULA;
59-
} elseif (preg_match('/^[\+\-]?(\d+\\.?\d*|\d*\\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $value)) {
72+
}
73+
if (preg_match('/^[\+\-]?(\d+\\.?\d*|\d*\\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $value)) {
6074
$tValue = ltrim($value, '+-');
61-
if (is_string($value) && strlen($tValue) > 1 && $tValue[0] === '0' && $tValue[1] !== '.') {
75+
if (strlen($tValue) > 1 && $tValue[0] === '0' && $tValue[1] !== '.') {
6276
return DataType::TYPE_STRING;
6377
} elseif ((!str_contains($value, '.')) && ($value > PHP_INT_MAX)) {
6478
return DataType::TYPE_STRING;
@@ -67,11 +81,10 @@ public static function dataTypeForValue(mixed $value): string
6781
}
6882

6983
return DataType::TYPE_NUMERIC;
70-
} elseif (is_string($value)) {
71-
$errorCodes = DataType::getErrorCodes();
72-
if (isset($errorCodes[$value])) {
73-
return DataType::TYPE_ERROR;
74-
}
84+
}
85+
$errorCodes = DataType::getErrorCodes();
86+
if (isset($errorCodes[$value])) {
87+
return DataType::TYPE_ERROR;
7588
}
7689

7790
return DataType::TYPE_STRING;

src/PhpSpreadsheet/Chart/Axis.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function __construct()
3737
/**
3838
* Axis Number.
3939
*
40-
* @var mixed[]
40+
* @var array{format: string, source_linked: int, numeric: ?bool}
4141
*/
4242
private array $axisNumber = [
4343
'format' => self::FORMAT_CODE_GENERAL,

src/PhpSpreadsheet/Chart/DataSeriesValues.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -451,12 +451,14 @@ public function refresh(Worksheet $worksheet, bool $flatten = true): void
451451
if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
452452
$this->dataValues = Functions::flattenArray($newDataValues);
453453
} else {
454-
$newArray = array_values(array_shift($newDataValues));
454+
/** @var array<int, array> */
455+
$newDataValuesx = $newDataValues;
456+
$newArray = array_values(array_shift($newDataValuesx) ?? []);
455457
foreach ($newArray as $i => $newDataSet) {
456458
$newArray[$i] = [$newDataSet];
457459
}
458460

459-
foreach ($newDataValues as $newDataSet) {
461+
foreach ($newDataValuesx as $newDataSet) {
460462
$i = 0;
461463
foreach ($newDataSet as $newDataVal) {
462464
array_unshift($newArray[$i++], $newDataVal);

src/PhpSpreadsheet/Chart/Properties.php

+19-2
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,16 @@ public function getShadowProperty($elements): array|string|null
647647
'alpha' => $this->shadowColor->getAlpha(),
648648
];
649649
}
650+
$retVal = $this->getArrayElementsValue($this->shadowProperties, $elements);
651+
if (is_scalar($retVal)) {
652+
$retVal = (string) $retVal;
653+
} elseif ($retVal !== null && !is_array($retVal)) {
654+
// @codeCoverageIgnoreStart
655+
throw new Exception('Unexpected value for shadowProperty');
656+
// @codeCoverageIgnoreEnd
657+
}
650658

651-
return $this->getArrayElementsValue($this->shadowProperties, $elements);
659+
return $retVal;
652660
}
653661

654662
public function getShadowArray(): array
@@ -825,7 +833,16 @@ public function setLineStyleProperty(string $propertyName, mixed $value): self
825833
*/
826834
public function getLineStyleProperty(array|string $elements): ?string
827835
{
828-
return $this->getArrayElementsValue($this->lineStyleProperties, $elements);
836+
$retVal = $this->getArrayElementsValue($this->lineStyleProperties, $elements);
837+
if (is_scalar($retVal)) {
838+
$retVal = (string) $retVal;
839+
} elseif ($retVal !== null) {
840+
// @codeCoverageIgnoreStart
841+
throw new Exception('Unexpected value for lineStyleProperty');
842+
// @codeCoverageIgnoreEnd
843+
}
844+
845+
return $retVal;
829846
}
830847

831848
protected const ARROW_SIZES = [

src/PhpSpreadsheet/ReferenceHelper.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ public function insertNewBefore(
444444
if ($cell->getDataType() === DataType::TYPE_FORMULA) {
445445
// Formula should be adjusted
446446
$worksheet->getCell($newCoordinate)
447-
->setValue($this->updateFormulaReferences($cell->getValue(), $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle(), true));
447+
->setValue($this->updateFormulaReferences($cell->getValueString(), $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle(), true));
448448
} else {
449449
// Cell value should not be adjusted
450450
$worksheet->getCell($newCoordinate)->setValueExplicit($cell->getValue(), $cell->getDataType());
@@ -457,7 +457,7 @@ public function insertNewBefore(
457457
but we do still need to adjust any formulae in those cells */
458458
if ($cell->getDataType() === DataType::TYPE_FORMULA) {
459459
// Formula should be adjusted
460-
$cell->setValue($this->updateFormulaReferences($cell->getValue(), $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle(), true));
460+
$cell->setValue($this->updateFormulaReferences($cell->getValueString(), $beforeCellAddress, $numberOfColumns, $numberOfRows, $worksheet->getTitle(), true));
461461
}
462462
}
463463
}
@@ -897,7 +897,7 @@ public function updateNamedFormulae(Spreadsheet $spreadsheet, string $oldName =
897897
foreach ($sheet->getCoordinates(false) as $coordinate) {
898898
$cell = $sheet->getCell($coordinate);
899899
if ($cell->getDataType() === DataType::TYPE_FORMULA) {
900-
$formula = $cell->getValue();
900+
$formula = $cell->getValueString();
901901
if (str_contains($formula, $oldName)) {
902902
$formula = str_replace("'" . $oldName . "'!", "'" . $newName . "'!", $formula);
903903
$formula = str_replace($oldName . '!', $newName . '!', $formula);

src/PhpSpreadsheet/RichText/RichText.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public function __construct(?Cell $cell = null)
2727
// Rich-Text string attached to cell?
2828
if ($cell !== null) {
2929
// Add cell text and style
30-
if ($cell->getValue() != '') {
31-
$objRun = new Run($cell->getValue());
30+
if ($cell->getValueString() !== '') {
31+
$objRun = new Run($cell->getValueString());
3232
$objRun->setFont(clone $cell->getWorksheet()->getStyle($cell->getCoordinate())->getFont());
3333
$this->addText($objRun);
3434
}

src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,15 @@ private function polynomialRegression(int $order, array $yValues, array $xValues
159159
$coefficients = [];
160160
for ($i = 0; $i < $C->rows; ++$i) {
161161
$r = $C->getValue($i + 1, 1); // row and column are origin-1
162-
if (abs($r) <= 10 ** (-9)) {
162+
if (!is_numeric($r) || abs($r) <= 10 ** (-9)) {
163163
$r = 0;
164+
} else {
165+
$r += 0;
164166
}
165167
$coefficients[] = $r;
166168
}
167169

168-
$this->intersect = array_shift($coefficients);
170+
$this->intersect = (float) array_shift($coefficients);
169171
// Phpstan is correct
170172
//* @phpstan-ignore-next-line
171173
$this->slope = $coefficients;

0 commit comments

Comments
 (0)