[php-src] PR #23556: array_chunk(): Fill packed chunks directly when keys are not preserved
| From: | mehmetcansahin | Date: | Thu, 03 Sep 2026 13:28:39 +0000 |
| Subject: | [php-src] PR #23556: array_chunk(): Fill packed chunks directly when keys are not preserved | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-38282@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/23556
Author: mehmetcansahin
When
$preserve_keys is false (the default), every chunk is a list of at
most $size elements. array_chunk() now fills each chunk directly using
ZEND_HASH_FILL_PACKED instead of calling zend_hash_next_index_insert() for
each element.
The input is traversed through its element storage using a stride computed once, allowing packed and
mixed arrays to share the same loop. Holes (IS_UNDEF entries) are skipped, and
references with a refcount of one are unwrapped as before. The key-preserving insertion logic and
behavior remain unchanged.
### Benchmarks
array_chunk($input, $size, false) on an Apple M1 using a release build (best of three
runs). Base commit: ec93b0b941dc.
| input | size | repetitions | base | this PR | speedup |
|---|---:|---:|---:|---:|---:|
| packed, n=100 | 10 | 200,000 | 144.5 ms | 69.7 ms | 2.1× |
| packed, n=1,000 | 10 | 20,000 | 139.9 ms | 64.0 ms | 2.2× |
| packed, n=1,000 | 100 | 20,000 | 105.3 ms | 38.5 ms | 2.7× |
| packed, n=100,000 | 100 | 200 | 110.7 ms | 38.9 ms | 2.8× |
| string keys, n=1,000 | 10 | 20,000 | 140.0 ms | 64.1 ms | 2.2× |
Control check with $preserve_keys = true (packed input, n = 1,000,
$size = 10, 20,000 repetitions): 189.3 ms → 181.3 ms; no regression observed.
<details>
<summary>Benchmark script</summary>
```php
<?php
function bench(string $label, array $input, int $size, bool $preserve, int $reps): void {
$best = PHP_FLOAT_MAX;
for ($run = 0; $run < 3; $run++) {
$t = hrtime(true);
for ($r = 0; $r < $reps; $r++) {
array_chunk($input, $size, $preserve);
}
$best = min($best, (hrtime(true) - $t) / 1e6);
}
printf("%-28s size=%-5d x%-7d best: %8.1f ms\n", $label, $size, $reps, $best);
}
$hash = [];
for ($i = 0; $i < 1000; $i++) { $hash["k$i"] = $i; }
bench('packed n=100', range(0, 99), 10, false, 200000);
bench('packed n=1000', range(0, 999), 10, false, 20000);
bench('packed n=1000', range(0, 999), 100, false, 20000);
bench('packed n=100000', range(0, 99999), 100, false, 200);
bench('string keys n=1000', $hash, 10, false, 20000);
bench('packed n=1000 preserve', range(0, 999), 10, true, 20000);
```
</details>