[php-src] PR #23886: PHP array_splice(): Presize the result when nothing is removed
| From: | mehmetcansahin | Date: | Thu, 24 Sep 2026 12:33:58 +0000 |
| Subject: | [php-src] PR #23886: PHP array_splice(): Presize the result when nothing is removed | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-38772@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/23886
Author: mehmetcansahin
This PR speeds up
array_splice() when inserting without removing elements by allocating
enough space upfront, avoiding repeated growth. Behavior is unchanged.
Inserting one element in the middle of an array on Apple M1 (release build), using the median of
seven runs per build:
| input | base | this PR | speedup |
|---|---:|---:|---:|
| packed, n=16 | 99.8 ns | 77.7 ns | 1.28× |
| packed, n=100,000 | 421 µs | 401 µs | within noise¹ |
| string keys, n=1,000 | 7.70 µs | 5.82 µs | 1.32× |
| string keys, n=100,000 | 1.74 ms | 1.05 ms | 1.66× |
¹ Across the seven runs, base ranged 413–427 µs and this PR 391–429 µs.
Inserting one element into an array with 100,000 string keys drops extra peak memory from 7.5 MiB to
5.0 MiB.
<details>
<summary>Benchmark scripts and methodology</summary>
Builds were benchmarked alternately. Each script run reports the lowest average time per iteration
across five batches, including the array_pop()/unset() that keeps the
array size constant.
Timing:
```php
<?php
function bench(string $label, array $a, int $reps): void {
$packed = array_is_list($a);
$mid = intdiv(count($a), 2);
$best = PHP_FLOAT_MAX;
for ($run = 0; $run < 5; $run++) {
$t = hrtime(true);
for ($r = 0; $r < $reps; $r++) {
array_splice($a, $mid, 0, [-1]);
if ($packed) {
array_pop($a);
} else {
unset($a[0]);
}
}
$best = min($best, (hrtime(true) - $t) / $reps);
}
printf("%-24s %10.1f ns/op\n", $label, $best);
}
$keys = fn(int $n) => array_combine(
array_map(fn($i) => "k$i", range(0, $n - 1)),
range(0, $n - 1)
);
bench('packed n=16', range(0, 15), 1000000);
bench('packed n=100,000', range(0, 99999), 1000);
bench('string keys n=1,000', $keys(1000), 50000);
bench('string keys n=100,000', $keys(100000), 300);
```
Extra peak memory, measured relative to usage before the call:
```php
<?php
$a = array_combine(
array_map(fn($i) => "k$i", range(0, 99999)),
range(0, 99999)
);
$before = memory_get_usage();
memory_reset_peak_usage();
array_splice($a, 50000, 0, [-1]);
printf(
"extra peak: %.1f MiB\n",
(memory_get_peak_usage() - $before) / 1048576
);
```
</details>