Skip to content

Commit 3ace47a

Browse files
authored
Merge branch 'master' into issue4629
2 parents 3b674b6 + 84f259b commit 3ace47a

File tree

23 files changed

+472
-19
lines changed

23 files changed

+472
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a
3232
- Performance improvement when working with large amounts of cells. [Issue #4607](https://github.com/PHPOffice/PhpSpreadsheet/issues/4607) [PR #4609](https://github.com/PHPOffice/PhpSpreadsheet/pull/4609)
3333
- Minor improvements to Calculation coverage. [PR #4624](https://github.com/PHPOffice/PhpSpreadsheet/pull/4624)
3434
- Conditional formatting in extLst. [Issue #4629](https://github.com/PHPOffice/PhpSpreadsheet/issues/4629) [PR #4633](https://github.com/PHPOffice/PhpSpreadsheet/pull/4633)
35+
- Php8.5 deprecates use of null as array index. [PR #4634](https://github.com/PHPOffice/PhpSpreadsheet/pull/4634)
3536

3637
## 2025-09-03 - 5.1.0
3738

src/PhpSpreadsheet/Calculation/Calculation.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,7 @@ private static function resizeMatricesExtend(array &$matrix1, array &$matrix2, i
888888
}
889889
}
890890
if ($matrix1Rows < $matrix2Rows) {
891-
$x = ($matrix1Rows === 1) ? $matrix1[0] : array_fill(0, $matrix1Columns, null);
891+
$x = ($matrix1Rows === 1) ? $matrix1[0] : array_fill(0, $matrix2Columns, null);
892892
for ($i = $matrix1Rows; $i < $matrix2Rows; ++$i) {
893893
$matrix1[$i] = $x;
894894
}
@@ -1699,7 +1699,7 @@ private function processTokenStack(false|array $tokens, ?string $cellID = null,
16991699
return $this->raiseFormulaError($e->getMessage(), $e->getCode(), $e);
17001700
}
17011701
}
1702-
} elseif (!is_numeric($token) && !is_object($token) && isset(self::BINARY_OPERATORS[$token])) {
1702+
} elseif (!is_numeric($token) && !is_object($token) && isset($token, self::BINARY_OPERATORS[$token])) {
17031703
// if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
17041704
// We must have two operands, error if we don't
17051705
$operand2Data = $stack->pop();

src/PhpSpreadsheet/Calculation/CalculationLocale.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ protected static function loadLocales(): void
6363
$filename = substr($filename, strlen($localeFileDirectory));
6464
if ($filename != 'en') {
6565
self::$validLocaleLanguages[] = $filename;
66+
$subdirs = glob("$localeFileDirectory$filename/*", GLOB_ONLYDIR) ?: [];
67+
foreach ($subdirs as $subdir) {
68+
$subdirx = basename($subdir);
69+
self::$validLocaleLanguages[] = "{$filename}_{$subdirx}";
70+
}
6671
}
6772
}
6873
}

src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,9 @@ protected static function getFilteredColumn(array $database, ?int $field, array
117117
/** @var mixed[] $row */
118118
foreach ($database as $rowKey => $row) {
119119
$keys = array_keys($row);
120-
$key = $keys[$field] ?? null;
120+
$key = ($field === null) ? null : ($keys[$field] ?? null);
121121
$columnKey = $key ?? 'A';
122-
$columnData[$rowKey][$columnKey] = $row[$key] ?? $defaultReturnColumnValue;
122+
$columnData[$rowKey][$columnKey] = ($key === null) ? $defaultReturnColumnValue : ($row[$key] ?? $defaultReturnColumnValue);
123123
}
124124

125125
return $columnData;

src/PhpSpreadsheet/Calculation/Engine/BranchPruner.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public function initialiseForLoop(): void
7878

7979
private function initialiseCondition(): void
8080
{
81-
if (isset($this->conditionMap[$this->pendingStoreKey]) && $this->conditionMap[$this->pendingStoreKey]) {
81+
if (isset($this->pendingStoreKey, $this->conditionMap[$this->pendingStoreKey]) && $this->conditionMap[$this->pendingStoreKey]) {
8282
$this->currentCondition = $this->pendingStoreKey;
8383
$stackDepth = count($this->storeKeysStack);
8484
if ($stackDepth > 1) {
@@ -90,7 +90,7 @@ private function initialiseCondition(): void
9090

9191
private function initialiseThen(): void
9292
{
93-
if (isset($this->thenMap[$this->pendingStoreKey]) && $this->thenMap[$this->pendingStoreKey]) {
93+
if (isset($this->pendingStoreKey, $this->thenMap[$this->pendingStoreKey]) && $this->thenMap[$this->pendingStoreKey]) {
9494
$this->currentOnlyIf = $this->pendingStoreKey;
9595
} elseif (
9696
isset($this->previousStoreKey, $this->thenMap[$this->previousStoreKey])
@@ -102,7 +102,7 @@ private function initialiseThen(): void
102102

103103
private function initialiseElse(): void
104104
{
105-
if (isset($this->elseMap[$this->pendingStoreKey]) && $this->elseMap[$this->pendingStoreKey]) {
105+
if (isset($this->pendingStoreKey, $this->elseMap[$this->pendingStoreKey]) && $this->elseMap[$this->pendingStoreKey]) {
106106
$this->currentOnlyIfNot = $this->pendingStoreKey;
107107
} elseif (
108108
isset($this->previousStoreKey, $this->elseMap[$this->previousStoreKey])

src/PhpSpreadsheet/Collection/Cells.php

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,25 @@ class Cells
4343
*/
4444
private array $index = [];
4545

46+
/**
47+
* Flag to avoid sorting the index every time.
48+
*/
49+
private bool $indexSorted = false;
50+
51+
/**
52+
* Index keys cache to avoid recalculating on large arrays.
53+
*
54+
* @var null|string[]
55+
*/
56+
private ?array $indexKeysCache = null;
57+
58+
/**
59+
* Index values cache to avoid recalculating on large arrays.
60+
*
61+
* @var null|int[]
62+
*/
63+
private ?array $indexValuesCache = null;
64+
4665
/**
4766
* Prefix used to uniquely identify cache data for this worksheet.
4867
*/
@@ -112,6 +131,10 @@ public function delete(string $cellCoordinate): void
112131

113132
unset($this->index[$cellCoordinate]);
114133

134+
// Clear index caches
135+
$this->indexKeysCache = null;
136+
$this->indexValuesCache = null;
137+
115138
// Delete the entry from cache
116139
$this->cache->delete($this->cachePrefix . $cellCoordinate);
117140
}
@@ -123,7 +146,12 @@ public function delete(string $cellCoordinate): void
123146
*/
124147
public function getCoordinates(): array
125148
{
126-
return array_keys($this->index);
149+
// Build or rebuild index keys cache
150+
if ($this->indexKeysCache === null) {
151+
$this->indexKeysCache = array_keys($this->index);
152+
}
153+
154+
return $this->indexKeysCache;
127155
}
128156

129157
/**
@@ -133,9 +161,21 @@ public function getCoordinates(): array
133161
*/
134162
public function getSortedCoordinates(): array
135163
{
136-
asort($this->index);
164+
// Sort only when required
165+
if (!$this->indexSorted) {
166+
asort($this->index);
167+
$this->indexSorted = true;
168+
// Clear unsorted cache
169+
$this->indexKeysCache = null;
170+
$this->indexValuesCache = null;
171+
}
137172

138-
return array_keys($this->index);
173+
// Build or rebuild index keys cache
174+
if ($this->indexKeysCache === null) {
175+
$this->indexKeysCache = array_keys($this->index);
176+
}
177+
178+
return $this->indexKeysCache;
139179
}
140180

141181
/**
@@ -145,9 +185,19 @@ public function getSortedCoordinates(): array
145185
*/
146186
public function getSortedCoordinatesInt(): array
147187
{
148-
asort($this->index);
188+
if (!$this->indexSorted) {
189+
asort($this->index);
190+
$this->indexSorted = true;
191+
// Clear unsorted cache
192+
$this->indexKeysCache = null;
193+
$this->indexValuesCache = null;
194+
}
149195

150-
return array_values($this->index);
196+
if ($this->indexValuesCache === null) {
197+
$this->indexValuesCache = array_values($this->index);
198+
}
199+
200+
return $this->indexValuesCache;
151201
}
152202

153203
/**
@@ -300,6 +350,11 @@ public function cloneCellCollection(Worksheet $worksheet): static
300350
}
301351
}
302352

353+
// Clear index sorted flag and index caches
354+
$newCollection->indexSorted = false;
355+
$newCollection->indexKeysCache = null;
356+
$newCollection->indexValuesCache = null;
357+
303358
return $newCollection;
304359
}
305360

@@ -390,6 +445,11 @@ public function add(string $cellCoordinate, Cell $cell): Cell
390445
/** @var int $row */
391446
$this->index[$cellCoordinate] = (--$row * self::MAX_COLUMN_ID) + Coordinate::columnIndexFromString((string) $column);
392447

448+
// Clear index sorted flag and index caches
449+
$this->indexSorted = false;
450+
$this->indexKeysCache = null;
451+
$this->indexValuesCache = null;
452+
393453
$this->currentCoordinate = $cellCoordinate;
394454
$this->currentCell = $cell;
395455
$this->currentCellIsDirty = true;
@@ -444,6 +504,11 @@ public function unsetWorksheetCells(): void
444504

445505
$this->index = [];
446506

507+
// Clear index sorted flag and index caches
508+
$this->indexSorted = false;
509+
$this->indexKeysCache = null;
510+
$this->indexValuesCache = null;
511+
447512
// detach ourself from the worksheet, so that it can then delete this object successfully
448513
$this->parent = null;
449514
}

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1277,7 +1277,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
12771277
// Set comment properties
12781278
$comment = $docSheet->getComment([(int) $column + 1, (int) $row + 1]);
12791279
$comment->getFillColor()->setRGB($fillColor);
1280-
if (isset($drowingImages[$fillImageRelId])) {
1280+
if (isset($fillImageRelId, $drowingImages[$fillImageRelId])) {
12811281
$objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
12821282
$objDrawing->setName($fillImageTitle);
12831283
$imagePath = str_replace(['../', '/xl/'], 'xl/', $drowingImages[$fillImageRelId]);

src/PhpSpreadsheet/Shared/StringHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ public static function UTF8toBIFF8UnicodeLong(string $textValue): string
420420
*/
421421
public static function convertEncoding(string $textValue, string $to, string $from): string
422422
{
423-
if (self::getIsIconvEnabled()) {
423+
if (static::getIsIconvEnabled()) {
424424
$result = iconv($from, $to . self::$iconvOptions, $textValue);
425425
if (false !== $result) {
426426
return $result;

src/PhpSpreadsheet/Worksheet/Worksheet.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3100,9 +3100,30 @@ public function rangeToArrayYieldRows(
31003100

31013101
$index = ($row - 1) * AddressRange::MAX_COLUMN_INT + 1;
31023102
$indexPlus = $index + AddressRange::MAX_COLUMN_INT - 1;
3103+
3104+
// Binary search to quickly approach the correct index
3105+
$keyIndex = intdiv($keysCount, 2);
3106+
$boundLow = 0;
3107+
$boundHigh = $keysCount - 1;
3108+
while ($boundLow <= $boundHigh) {
3109+
$keyIndex = intdiv($boundLow + $boundHigh, 2);
3110+
if ($keys[$keyIndex] < $index) {
3111+
$boundLow = $keyIndex + 1;
3112+
} elseif ($keys[$keyIndex] > $index) {
3113+
$boundHigh = $keyIndex - 1;
3114+
} else {
3115+
break;
3116+
}
3117+
}
3118+
3119+
// Realign to the proper index value
3120+
while ($keyIndex > 0 && $keys[$keyIndex] > $index) {
3121+
--$keyIndex;
3122+
}
31033123
while ($keyIndex < $keysCount && $keys[$keyIndex] < $index) {
31043124
++$keyIndex;
31053125
}
3126+
31063127
while ($keyIndex < $keysCount && $keys[$keyIndex] <= $indexPlus) {
31073128
$key = $keys[$keyIndex];
31083129
$thisRow = intdiv($key - 1, AddressRange::MAX_COLUMN_INT) + 1;

src/PhpSpreadsheet/Writer/Pdf/Dompdf.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function save($filename, int $flags = 0): void
7676
public function specialErrorHandler(int $errno, string $errstr, string $filename, int $lineno): bool
7777
{
7878
if ($errno === E_DEPRECATED) {
79-
if (preg_match('/canonical|imagedestroy|http_get_last_response_headers/', $errstr) === 1) {
79+
if (preg_match('/canonical|imagedestroy|http_get_last_response_headers|Using null as an array offset/', $errstr) === 1) {
8080
return true;
8181
}
8282
}

0 commit comments

Comments
 (0)