Skip to content

Commit 9f87d7c

Browse files
authored
Merge pull request #3834 from sj-i/dedupe-null-rows
Reduce memory consumption of Worksheet::rangeToArray() when many empty rows are read
2 parents c9ef889 + a034ab8 commit 9f87d7c

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
8484
- COUNTIFS Does Not Require xlfn. [Issue #3819](https://github.com/PHPOffice/PhpSpreadsheet/issues/3819) [PR #3827](https://github.com/PHPOffice/PhpSpreadsheet/pull/3827)
8585
- Strip `xlfn.` and `xlws.` from Formula Translations. [Issue #3819](https://github.com/PHPOffice/PhpSpreadsheet/issues/3819) [PR #3828](https://github.com/PHPOffice/PhpSpreadsheet/pull/3828)
8686
- Recurse directories searching for font file. [Issue #2809](https://github.com/PHPOffice/PhpSpreadsheet/issues/2809) [PR #3830](https://github.com/PHPOffice/PhpSpreadsheet/pull/3830)
87+
- Reduce memory consumption of Worksheet::rangeToArray() when many empty rows are read. [Issue #3814](https://github.com/PHPOffice/PhpSpreadsheet/pull/3814) [PR #3834](https://github.com/PHPOffice/PhpSpreadsheet/pull/3834)
8788

8889
## 1.29.0 - 2023-06-15
8990

src/PhpSpreadsheet/Worksheet/Worksheet.php

+34-1
Original file line numberDiff line numberDiff line change
@@ -3233,13 +3233,16 @@ public function rangeToArray(
32333233
$maxRow = $rangeEnd[1];
32343234

32353235
++$maxCol;
3236+
$nullRow = $this->buildNullRow($nullValue, $minCol, $maxCol, $returnCellRef, $ignoreHidden);
3237+
32363238
// Loop through rows
32373239
$r = -1;
32383240
for ($row = $minRow; $row <= $maxRow; ++$row) {
32393241
if (($ignoreHidden === true) && ($this->getRowDimension($row)->getVisible() === false)) {
32403242
continue;
32413243
}
32423244
$rowRef = $returnCellRef ? $row : ++$r;
3245+
$returnValue[$rowRef] = $nullRow;
32433246
$c = -1;
32443247
// Loop through columns in the current row
32453248
for ($col = $minCol; $col !== $maxCol; ++$col) {
@@ -3250,7 +3253,6 @@ public function rangeToArray(
32503253
// Using getCell() will create a new cell if it doesn't already exist. We don't want that to happen
32513254
// so we test and retrieve directly against cellCollection
32523255
$cell = $this->getCellCollection()->get("{$col}{$row}");
3253-
$returnValue[$rowRef][$columnRef] = $nullValue;
32543256
if ($cell !== null) {
32553257
$returnValue[$rowRef][$columnRef] = $this->cellToArray($cell, $calculateFormulas, $formatData, $nullValue);
32563258
}
@@ -3261,6 +3263,37 @@ public function rangeToArray(
32613263
return $returnValue;
32623264
}
32633265

3266+
/**
3267+
* Prepare a row data filled with null values to deduplicate the memory areas for empty rows.
3268+
*
3269+
* @param mixed $nullValue Value returned in the array entry if a cell doesn't exist
3270+
* @param string $minCol Start column of the range
3271+
* @param string $maxCol End column of the range
3272+
* @param bool $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero
3273+
* True - Return rows and columns indexed by their actual row and column IDs
3274+
* @param bool $ignoreHidden False - Return values for rows/columns even if they are defined as hidden.
3275+
* True - Don't return values for rows/columns that are defined as hidden.
3276+
*/
3277+
private function buildNullRow(
3278+
mixed $nullValue,
3279+
string $minCol,
3280+
string $maxCol,
3281+
bool $returnCellRef,
3282+
bool $ignoreHidden,
3283+
): array {
3284+
$nullRow = [];
3285+
$c = -1;
3286+
for ($col = $minCol; $col !== $maxCol; ++$col) {
3287+
if (($ignoreHidden === true) && ($this->getColumnDimension($col)->getVisible() === false)) {
3288+
continue;
3289+
}
3290+
$columnRef = $returnCellRef ? $col : ++$c;
3291+
$nullRow[$columnRef] = $nullValue;
3292+
}
3293+
3294+
return $nullRow;
3295+
}
3296+
32643297
private function validateNamedRange(string $definedName, bool $returnNullIfInvalid = false): ?DefinedName
32653298
{
32663299
$namedRange = DefinedName::resolveName($definedName, $this);

0 commit comments

Comments
 (0)