Skip to content

Commit 216db02

Browse files
authored
Merge pull request #4565 from oleibman/issue4588
Create Uninitialized Cell If Used in Calculation
2 parents ea97afb + fa2c329 commit 216db02

File tree

17 files changed

+123
-78
lines changed

17 files changed

+123
-78
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,12 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a
3636

3737
### Fixed
3838

39+
- Create uninitialized cell if used in calculation. [Issue #4558](https://github.com/PHPOffice/PhpSpreadsheet/issues/4558) [Issue #4530](https://github.com/PHPOffice/PhpSpreadsheet/issues/4530) [PR #4565](https://github.com/PHPOffice/PhpSpreadsheet/pull/4565)
3940
- Shared/Date::isDateTime handle cells which calculate as arrays. [Issue #4557](https://github.com/PHPOffice/PhpSpreadsheet/issues/4557) [PR #4562](https://github.com/PHPOffice/PhpSpreadsheet/pull/4562)
4041
- Xlsx Writer eliminate xml:space from non-text nodes. [Issue #4542](https://github.com/PHPOffice/PhpSpreadsheet/issues/4542) [PR #4556](https://github.com/PHPOffice/PhpSpreadsheet/pull/4556)## 2025-07-23 - 4.5.0
4142

43+
## 2025-07-23 - 4.5.0
44+
4245
### Added
4346

4447
- Add to all readers the option to allow or forbid fetching external images. This is unconditionally allowed now. The default will be set to "allow", so no code changes are necessary. However, we are giving consideration to changing the default. [PR #4543](https://github.com/PHPOffice/PhpSpreadsheet/pull/4543)

src/PhpSpreadsheet/Calculation/Calculation.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2010,6 +2010,9 @@ private function processTokenStack(false|array $tokens, ?string $cellID = null,
20102010
$this->debugLog->writeDebugLog('Evaluating Cell %s in worksheet %s', $cellRef, $matches[2]);
20112011
if ($pCellParent !== null && $this->spreadsheet !== null) {
20122012
$cellSheet = $this->spreadsheet->getSheetByName($matches[2]);
2013+
if ($cellSheet && !$cellSheet->cellExists($cellRef)) {
2014+
$cellSheet->setCellValue($cellRef, null);
2015+
}
20132016
if ($cellSheet && $cellSheet->cellExists($cellRef)) {
20142017
$cellValue = $this->extractCellRange($cellRef, $this->spreadsheet->getSheetByName($matches[2]), false);
20152018
$cell->attach($pCellParent);
@@ -2514,7 +2517,7 @@ protected function raiseFormulaError(string $errorMessage, int $code = 0, ?Throw
25142517
*
25152518
* @return mixed[] Array of values in range if range contains more than one element. Otherwise, a single value is returned.
25162519
*/
2517-
public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet = null, bool $resetLog = true): array
2520+
public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet = null, bool $resetLog = true, bool $createCell = false): array
25182521
{
25192522
// Return value
25202523
/** @var mixed[][] */
@@ -2536,6 +2539,9 @@ public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet =
25362539
if (!isset($aReferences[1])) {
25372540
// Single cell in range
25382541
sscanf($aReferences[0], '%[A-Z]%d', $currentCol, $currentRow);
2542+
if ($createCell && $worksheet !== null && !$worksheet->cellExists($aReferences[0])) {
2543+
$worksheet->setCellValue($aReferences[0], null);
2544+
}
25392545
if ($worksheet !== null && $worksheet->cellExists($aReferences[0])) {
25402546
$temp = $worksheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
25412547
if ($this->getInstanceArrayReturnType() === self::RETURN_ARRAY_AS_ARRAY) {
@@ -2552,6 +2558,9 @@ public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet =
25522558
foreach ($aReferences as $reference) {
25532559
// Extract range
25542560
sscanf($reference, '%[A-Z]%d', $currentCol, $currentRow);
2561+
if ($createCell && $worksheet !== null && !$worksheet->cellExists($reference)) {
2562+
$worksheet->setCellValue($reference, null);
2563+
}
25552564
if ($worksheet !== null && $worksheet->cellExists($reference)) {
25562565
$temp = $worksheet->getCell($reference)->getCalculatedValue($resetLog);
25572566
if ($this->getInstanceArrayReturnType() === self::RETURN_ARRAY_AS_ARRAY) {

src/PhpSpreadsheet/Calculation/Financial/Amortization.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@ public static function AMORDEGRC(
5454
$salvage = Functions::flattenSingleValue($salvage);
5555
$period = Functions::flattenSingleValue($period);
5656
$rate = Functions::flattenSingleValue($rate);
57-
$basis = ($basis === null)
58-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
59-
: Functions::flattenSingleValue($basis);
57+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
6058

6159
try {
6260
$cost = FinancialValidations::validateFloat($cost);
@@ -141,9 +139,7 @@ public static function AMORLINC(
141139
$salvage = Functions::flattenSingleValue($salvage);
142140
$period = Functions::flattenSingleValue($period);
143141
$rate = Functions::flattenSingleValue($rate);
144-
$basis = ($basis === null)
145-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
146-
: Functions::flattenSingleValue($basis);
142+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
147143

148144
try {
149145
$cost = FinancialValidations::validateFloat($cost);

src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ public static function futureValue(
3838
): string|float {
3939
$rate = Functions::flattenSingleValue($rate);
4040
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
41-
$payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment);
42-
$presentValue = ($presentValue === null) ? 0.0 : Functions::flattenSingleValue($presentValue);
43-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
41+
$payment = Functions::flattenSingleValue($payment) ?? 0.0;
42+
$presentValue = Functions::flattenSingleValue($presentValue) ?? 0.0;
43+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
4444

4545
try {
4646
$rate = CashFlowValidations::validateRate($rate);
@@ -77,9 +77,9 @@ public static function presentValue(
7777
): string|float {
7878
$rate = Functions::flattenSingleValue($rate);
7979
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
80-
$payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment);
81-
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
82-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
80+
$payment = Functions::flattenSingleValue($payment) ?? 0.0;
81+
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
82+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
8383

8484
try {
8585
$rate = CashFlowValidations::validateRate($rate);
@@ -122,8 +122,8 @@ public static function periods(
122122
$rate = Functions::flattenSingleValue($rate);
123123
$payment = Functions::flattenSingleValue($payment);
124124
$presentValue = Functions::flattenSingleValue($presentValue);
125-
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
126-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
125+
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
126+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
127127

128128
try {
129129
$rate = CashFlowValidations::validateRate($rate);

src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public static function interest(
4141
$presentValue = Functions::flattenSingleValue($presentValue);
4242
$start = Functions::flattenSingleValue($start);
4343
$end = Functions::flattenSingleValue($end);
44-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
44+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
4545

4646
try {
4747
$rate = CashFlowValidations::validateRate($rate);
@@ -104,7 +104,7 @@ public static function principal(
104104
$presentValue = Functions::flattenSingleValue($presentValue);
105105
$start = Functions::flattenSingleValue($start);
106106
$end = Functions::flattenSingleValue($end);
107-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
107+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
108108

109109
try {
110110
$rate = CashFlowValidations::validateRate($rate);

src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static function payment(
4343
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
4444
$presentValue = Functions::flattenSingleValue($presentValue);
4545
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
46-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
46+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
4747

4848
try {
4949
$interestRate = CashFlowValidations::validateRate($interestRate);
@@ -160,9 +160,9 @@ public static function rate(
160160
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
161161
$payment = Functions::flattenSingleValue($payment);
162162
$presentValue = Functions::flattenSingleValue($presentValue);
163-
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
164-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
165-
$guess = ($guess === null) ? 0.1 : Functions::flattenSingleValue($guess);
163+
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
164+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
165+
$guess = Functions::flattenSingleValue($guess) ?? 0.1;
166166

167167
try {
168168
$numberOfPeriods = CashFlowValidations::validateFloat($numberOfPeriods);

src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ public static function annuity(
2727
mixed $interestRate,
2828
mixed $numberOfPeriods,
2929
mixed $presentValue,
30-
mixed $futureValue = 0,
30+
mixed $futureValue = 0.0,
3131
mixed $type = FinancialConstants::PAYMENT_END_OF_PERIOD
3232
): string|float {
3333
$interestRate = Functions::flattenSingleValue($interestRate);
3434
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
3535
$presentValue = Functions::flattenSingleValue($presentValue);
36-
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
37-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
36+
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
37+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
3838

3939
try {
4040
$interestRate = CashFlowValidations::validateRate($interestRate);
@@ -83,7 +83,7 @@ public static function interestPayment(
8383
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
8484
$presentValue = Functions::flattenSingleValue($presentValue);
8585
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
86-
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
86+
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
8787

8888
try {
8989
$interestRate = CashFlowValidations::validateRate($interestRate);

src/PhpSpreadsheet/Calculation/Financial/Coupons.php

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@ public static function COUPDAYBS(
4949
$settlement = Functions::flattenSingleValue($settlement);
5050
$maturity = Functions::flattenSingleValue($maturity);
5151
$frequency = Functions::flattenSingleValue($frequency);
52-
$basis = ($basis === null)
53-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
54-
: Functions::flattenSingleValue($basis);
52+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
5553

5654
try {
5755
$settlement = FinancialValidations::validateSettlementDate($settlement);
@@ -110,9 +108,7 @@ public static function COUPDAYS(
110108
$settlement = Functions::flattenSingleValue($settlement);
111109
$maturity = Functions::flattenSingleValue($maturity);
112110
$frequency = Functions::flattenSingleValue($frequency);
113-
$basis = ($basis === null)
114-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
115-
: Functions::flattenSingleValue($basis);
111+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
116112

117113
try {
118114
$settlement = FinancialValidations::validateSettlementDate($settlement);
@@ -179,9 +175,7 @@ public static function COUPDAYSNC(
179175
$settlement = Functions::flattenSingleValue($settlement);
180176
$maturity = Functions::flattenSingleValue($maturity);
181177
$frequency = Functions::flattenSingleValue($frequency);
182-
$basis = ($basis === null)
183-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
184-
: Functions::flattenSingleValue($basis);
178+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
185179

186180
try {
187181
$settlement = FinancialValidations::validateSettlementDate($settlement);
@@ -244,9 +238,7 @@ public static function COUPNCD(
244238
$settlement = Functions::flattenSingleValue($settlement);
245239
$maturity = Functions::flattenSingleValue($maturity);
246240
$frequency = Functions::flattenSingleValue($frequency);
247-
$basis = ($basis === null)
248-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
249-
: Functions::flattenSingleValue($basis);
241+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
250242

251243
try {
252244
$settlement = FinancialValidations::validateSettlementDate($settlement);
@@ -296,9 +288,7 @@ public static function COUPNUM(
296288
$settlement = Functions::flattenSingleValue($settlement);
297289
$maturity = Functions::flattenSingleValue($maturity);
298290
$frequency = Functions::flattenSingleValue($frequency);
299-
$basis = ($basis === null)
300-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
301-
: Functions::flattenSingleValue($basis);
291+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
302292

303293
try {
304294
$settlement = FinancialValidations::validateSettlementDate($settlement);
@@ -355,9 +345,7 @@ public static function COUPPCD(
355345
$settlement = Functions::flattenSingleValue($settlement);
356346
$maturity = Functions::flattenSingleValue($maturity);
357347
$frequency = Functions::flattenSingleValue($frequency);
358-
$basis = ($basis === null)
359-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
360-
: Functions::flattenSingleValue($basis);
348+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
361349

362350
try {
363351
$settlement = FinancialValidations::validateSettlementDate($settlement);

src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,8 @@ public static function periodic(
6060
$settlement = Functions::flattenSingleValue($settlement);
6161
$rate = Functions::flattenSingleValue($rate);
6262
$parValue = ($parValue === null) ? 1000 : Functions::flattenSingleValue($parValue);
63-
$frequency = ($frequency === null)
64-
? FinancialConstants::FREQUENCY_ANNUAL
65-
: Functions::flattenSingleValue($frequency);
66-
$basis = ($basis === null)
67-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
68-
: Functions::flattenSingleValue($basis);
63+
$frequency = Functions::flattenSingleValue($frequency) ?? FinancialConstants::FREQUENCY_ANNUAL;
64+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
6965

7066
try {
7167
$issue = SecurityValidations::validateIssueDate($issue);
@@ -126,9 +122,7 @@ public static function atMaturity(
126122
$settlement = Functions::flattenSingleValue($settlement);
127123
$rate = Functions::flattenSingleValue($rate);
128124
$parValue = ($parValue === null) ? 1000 : Functions::flattenSingleValue($parValue);
129-
$basis = ($basis === null)
130-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
131-
: Functions::flattenSingleValue($basis);
125+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
132126

133127
try {
134128
$issue = SecurityValidations::validateIssueDate($issue);

src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ public static function price(
5353
$yield = Functions::flattenSingleValue($yield);
5454
$redemption = Functions::flattenSingleValue($redemption);
5555
$frequency = Functions::flattenSingleValue($frequency);
56-
$basis = ($basis === null)
57-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
58-
: Functions::flattenSingleValue($basis);
56+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
5957

6058
try {
6159
$settlement = SecurityValidations::validateSettlementDate($settlement);
@@ -120,9 +118,7 @@ public static function priceDiscounted(
120118
$maturity = Functions::flattenSingleValue($maturity);
121119
$discount = Functions::flattenSingleValue($discount);
122120
$redemption = Functions::flattenSingleValue($redemption);
123-
$basis = ($basis === null)
124-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
125-
: Functions::flattenSingleValue($basis);
121+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
126122

127123
try {
128124
$settlement = SecurityValidations::validateSettlementDate($settlement);
@@ -179,9 +175,7 @@ public static function priceAtMaturity(
179175
$issue = Functions::flattenSingleValue($issue);
180176
$rate = Functions::flattenSingleValue($rate);
181177
$yield = Functions::flattenSingleValue($yield);
182-
$basis = ($basis === null)
183-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
184-
: Functions::flattenSingleValue($basis);
178+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
185179

186180
try {
187181
$settlement = SecurityValidations::validateSettlementDate($settlement);
@@ -255,9 +249,7 @@ public static function received(
255249
$maturity = Functions::flattenSingleValue($maturity);
256250
$investment = Functions::flattenSingleValue($investment);
257251
$discount = Functions::flattenSingleValue($discount);
258-
$basis = ($basis === null)
259-
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
260-
: Functions::flattenSingleValue($basis);
252+
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;
261253

262254
try {
263255
$settlement = SecurityValidations::validateSettlementDate($settlement);

0 commit comments

Comments
 (0)