Skip to content

Create Uninitialized Cell If Used in Calculation #4565

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a

### Fixed

- 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)
- 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)
- 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

## 2025-07-23 - 4.5.0

### Added

- 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)
Expand Down
11 changes: 10 additions & 1 deletion src/PhpSpreadsheet/Calculation/Calculation.php
Original file line number Diff line number Diff line change
Expand Up @@ -2010,6 +2010,9 @@ private function processTokenStack(false|array $tokens, ?string $cellID = null,
$this->debugLog->writeDebugLog('Evaluating Cell %s in worksheet %s', $cellRef, $matches[2]);
if ($pCellParent !== null && $this->spreadsheet !== null) {
$cellSheet = $this->spreadsheet->getSheetByName($matches[2]);
if ($cellSheet && !$cellSheet->cellExists($cellRef)) {
$cellSheet->setCellValue($cellRef, null);
}
if ($cellSheet && $cellSheet->cellExists($cellRef)) {
$cellValue = $this->extractCellRange($cellRef, $this->spreadsheet->getSheetByName($matches[2]), false);
$cell->attach($pCellParent);
Expand Down Expand Up @@ -2514,7 +2517,7 @@ protected function raiseFormulaError(string $errorMessage, int $code = 0, ?Throw
*
* @return mixed[] Array of values in range if range contains more than one element. Otherwise, a single value is returned.
*/
public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet = null, bool $resetLog = true): array
public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet = null, bool $resetLog = true, bool $createCell = false): array
{
// Return value
/** @var mixed[][] */
Expand All @@ -2536,6 +2539,9 @@ public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet =
if (!isset($aReferences[1])) {
// Single cell in range
sscanf($aReferences[0], '%[A-Z]%d', $currentCol, $currentRow);
if ($createCell && $worksheet !== null && !$worksheet->cellExists($aReferences[0])) {
$worksheet->setCellValue($aReferences[0], null);
}
if ($worksheet !== null && $worksheet->cellExists($aReferences[0])) {
$temp = $worksheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
if ($this->getInstanceArrayReturnType() === self::RETURN_ARRAY_AS_ARRAY) {
Expand All @@ -2552,6 +2558,9 @@ public function extractCellRange(string &$range = 'A1', ?Worksheet $worksheet =
foreach ($aReferences as $reference) {
// Extract range
sscanf($reference, '%[A-Z]%d', $currentCol, $currentRow);
if ($createCell && $worksheet !== null && !$worksheet->cellExists($reference)) {
$worksheet->setCellValue($reference, null);
}
if ($worksheet !== null && $worksheet->cellExists($reference)) {
$temp = $worksheet->getCell($reference)->getCalculatedValue($resetLog);
if ($this->getInstanceArrayReturnType() === self::RETURN_ARRAY_AS_ARRAY) {
Expand Down
8 changes: 2 additions & 6 deletions src/PhpSpreadsheet/Calculation/Financial/Amortization.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ public static function AMORDEGRC(
$salvage = Functions::flattenSingleValue($salvage);
$period = Functions::flattenSingleValue($period);
$rate = Functions::flattenSingleValue($rate);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$cost = FinancialValidations::validateFloat($cost);
Expand Down Expand Up @@ -141,9 +139,7 @@ public static function AMORLINC(
$salvage = Functions::flattenSingleValue($salvage);
$period = Functions::flattenSingleValue($period);
$rate = Functions::flattenSingleValue($rate);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$cost = FinancialValidations::validateFloat($cost);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ public static function futureValue(
): string|float {
$rate = Functions::flattenSingleValue($rate);
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
$payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment);
$presentValue = ($presentValue === null) ? 0.0 : Functions::flattenSingleValue($presentValue);
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
$payment = Functions::flattenSingleValue($payment) ?? 0.0;
$presentValue = Functions::flattenSingleValue($presentValue) ?? 0.0;
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;

try {
$rate = CashFlowValidations::validateRate($rate);
Expand Down Expand Up @@ -77,9 +77,9 @@ public static function presentValue(
): string|float {
$rate = Functions::flattenSingleValue($rate);
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
$payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment);
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
$payment = Functions::flattenSingleValue($payment) ?? 0.0;
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;

try {
$rate = CashFlowValidations::validateRate($rate);
Expand Down Expand Up @@ -122,8 +122,8 @@ public static function periods(
$rate = Functions::flattenSingleValue($rate);
$payment = Functions::flattenSingleValue($payment);
$presentValue = Functions::flattenSingleValue($presentValue);
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;

try {
$rate = CashFlowValidations::validateRate($rate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static function interest(
$presentValue = Functions::flattenSingleValue($presentValue);
$start = Functions::flattenSingleValue($start);
$end = Functions::flattenSingleValue($end);
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;

try {
$rate = CashFlowValidations::validateRate($rate);
Expand Down Expand Up @@ -104,7 +104,7 @@ public static function principal(
$presentValue = Functions::flattenSingleValue($presentValue);
$start = Functions::flattenSingleValue($start);
$end = Functions::flattenSingleValue($end);
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;

try {
$rate = CashFlowValidations::validateRate($rate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public static function payment(
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
$presentValue = Functions::flattenSingleValue($presentValue);
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;

try {
$interestRate = CashFlowValidations::validateRate($interestRate);
Expand Down Expand Up @@ -160,9 +160,9 @@ public static function rate(
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
$payment = Functions::flattenSingleValue($payment);
$presentValue = Functions::flattenSingleValue($presentValue);
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
$guess = ($guess === null) ? 0.1 : Functions::flattenSingleValue($guess);
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;
$guess = Functions::flattenSingleValue($guess) ?? 0.1;

try {
$numberOfPeriods = CashFlowValidations::validateFloat($numberOfPeriods);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ public static function annuity(
mixed $interestRate,
mixed $numberOfPeriods,
mixed $presentValue,
mixed $futureValue = 0,
mixed $futureValue = 0.0,
mixed $type = FinancialConstants::PAYMENT_END_OF_PERIOD
): string|float {
$interestRate = Functions::flattenSingleValue($interestRate);
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
$presentValue = Functions::flattenSingleValue($presentValue);
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
$futureValue = Functions::flattenSingleValue($futureValue) ?? 0.0;
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;

try {
$interestRate = CashFlowValidations::validateRate($interestRate);
Expand Down Expand Up @@ -83,7 +83,7 @@ public static function interestPayment(
$numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods);
$presentValue = Functions::flattenSingleValue($presentValue);
$futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue);
$type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type);
$type = Functions::flattenSingleValue($type) ?? FinancialConstants::PAYMENT_END_OF_PERIOD;

try {
$interestRate = CashFlowValidations::validateRate($interestRate);
Expand Down
24 changes: 6 additions & 18 deletions src/PhpSpreadsheet/Calculation/Financial/Coupons.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ public static function COUPDAYBS(
$settlement = Functions::flattenSingleValue($settlement);
$maturity = Functions::flattenSingleValue($maturity);
$frequency = Functions::flattenSingleValue($frequency);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = FinancialValidations::validateSettlementDate($settlement);
Expand Down Expand Up @@ -110,9 +108,7 @@ public static function COUPDAYS(
$settlement = Functions::flattenSingleValue($settlement);
$maturity = Functions::flattenSingleValue($maturity);
$frequency = Functions::flattenSingleValue($frequency);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = FinancialValidations::validateSettlementDate($settlement);
Expand Down Expand Up @@ -179,9 +175,7 @@ public static function COUPDAYSNC(
$settlement = Functions::flattenSingleValue($settlement);
$maturity = Functions::flattenSingleValue($maturity);
$frequency = Functions::flattenSingleValue($frequency);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = FinancialValidations::validateSettlementDate($settlement);
Expand Down Expand Up @@ -244,9 +238,7 @@ public static function COUPNCD(
$settlement = Functions::flattenSingleValue($settlement);
$maturity = Functions::flattenSingleValue($maturity);
$frequency = Functions::flattenSingleValue($frequency);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = FinancialValidations::validateSettlementDate($settlement);
Expand Down Expand Up @@ -296,9 +288,7 @@ public static function COUPNUM(
$settlement = Functions::flattenSingleValue($settlement);
$maturity = Functions::flattenSingleValue($maturity);
$frequency = Functions::flattenSingleValue($frequency);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = FinancialValidations::validateSettlementDate($settlement);
Expand Down Expand Up @@ -355,9 +345,7 @@ public static function COUPPCD(
$settlement = Functions::flattenSingleValue($settlement);
$maturity = Functions::flattenSingleValue($maturity);
$frequency = Functions::flattenSingleValue($frequency);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = FinancialValidations::validateSettlementDate($settlement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,8 @@ public static function periodic(
$settlement = Functions::flattenSingleValue($settlement);
$rate = Functions::flattenSingleValue($rate);
$parValue = ($parValue === null) ? 1000 : Functions::flattenSingleValue($parValue);
$frequency = ($frequency === null)
? FinancialConstants::FREQUENCY_ANNUAL
: Functions::flattenSingleValue($frequency);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$frequency = Functions::flattenSingleValue($frequency) ?? FinancialConstants::FREQUENCY_ANNUAL;
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$issue = SecurityValidations::validateIssueDate($issue);
Expand Down Expand Up @@ -126,9 +122,7 @@ public static function atMaturity(
$settlement = Functions::flattenSingleValue($settlement);
$rate = Functions::flattenSingleValue($rate);
$parValue = ($parValue === null) ? 1000 : Functions::flattenSingleValue($parValue);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$issue = SecurityValidations::validateIssueDate($issue);
Expand Down
16 changes: 4 additions & 12 deletions src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ public static function price(
$yield = Functions::flattenSingleValue($yield);
$redemption = Functions::flattenSingleValue($redemption);
$frequency = Functions::flattenSingleValue($frequency);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = SecurityValidations::validateSettlementDate($settlement);
Expand Down Expand Up @@ -120,9 +118,7 @@ public static function priceDiscounted(
$maturity = Functions::flattenSingleValue($maturity);
$discount = Functions::flattenSingleValue($discount);
$redemption = Functions::flattenSingleValue($redemption);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = SecurityValidations::validateSettlementDate($settlement);
Expand Down Expand Up @@ -179,9 +175,7 @@ public static function priceAtMaturity(
$issue = Functions::flattenSingleValue($issue);
$rate = Functions::flattenSingleValue($rate);
$yield = Functions::flattenSingleValue($yield);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = SecurityValidations::validateSettlementDate($settlement);
Expand Down Expand Up @@ -255,9 +249,7 @@ public static function received(
$maturity = Functions::flattenSingleValue($maturity);
$investment = Functions::flattenSingleValue($investment);
$discount = Functions::flattenSingleValue($discount);
$basis = ($basis === null)
? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
: Functions::flattenSingleValue($basis);
$basis = Functions::flattenSingleValue($basis) ?? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD;

try {
$settlement = SecurityValidations::validateSettlementDate($settlement);
Expand Down
Loading