Repository navigation
Exponential analysis time with several int|float accumulators concatenated into a string in a loop (regression in 2.3.0) #15498
Description
Bug report
Since 2.3.0, analysis time grows exponentially with the number of loop accumulators that start as int ($a = 0), have (float) added to them in an inner loop (so their type becomes int|float), and are then concatenated into a string with .= in the outer loop. On 2.2.17 the same file is analysed in a few seconds.
We hit this on a real 600-line view template with 26 such accumulators: 2.3.0 / 2.3.1 never finish (worker Child process timed out after 600 seconds), 2.2.17 analyses the whole project in ~80 s.
Reproduced with a bare PHAR, no config, no extensions: php phpstan.phar analyse -l max file.php.
┌──────────────┬────────┬─────────────────┐
│ accumulators │ 2.2.17 │ 2.3.1 │
├──────────────┼────────┼─────────────────┤
│ 5 │ 5 s │ 16 s │
├──────────────┼────────┼─────────────────┤
│ 6 │ 6 s │ 41 s │
├──────────────┼────────┼─────────────────┤
│ 7 │ 6 s │ > 90 s (killed) │
└──────────────┴────────┴─────────────────┘
Also slow on 2.3.x-dev@0b9a9d1 (2026-10-18): the 6-variable case takes ~30 s, and the real-world file still times out.
Things that make it fast again (7 variables, ~4 s):
- initialising the accumulators as 0.0 instead of 0 (type stays float);
- replacing $out .= "..." with a plain assignment $out = "...".
Replacing the interpolation with . concatenation ($out .= $a . ' ' . $b ...) is still slow, so it doesn't look specific to string interpolation.
Code snippet that reproduces the problem
<?php declare(strict_types = 1);
/** @param list<list<array<string, mixed>>> $pl */
function t(array $pl): string {
$out = '';
foreach ($pl as $rows) {
$a = 0; $b = 0; $c = 0; $d = 0; $e = 0; $f = 0; $g = 0;
foreach ($rows as $r) {
$a = $a + (float) $r['a'];
$b = $b + (float) $r['b'];
$c = $c + (float) $r['c'];
$d = $d + (float) $r['d'];
$e = $e + (float) $r['e'];
$f = $f + (float) $r['f'];
$g = $g + (float) $r['g'];
}
$out .= "$a $b $c $d $e $f $g";
}
return $out;
}
(Remove variables to see the curve: 5 → 16 s, 6 → 41 s on 2.3.1.)
Code snippet that reproduces the problem
<?php declare(strict_types = 1);
/** @param list<list<array<string, mixed>>> $pl */
function t(array $pl): string {
$out = '';
foreach ($pl as $rows) {
$a = 0; $b = 0; $c = 0; $d = 0; $e = 0; $f = 0; $g = 0;
foreach ($rows as $r) {
$a = $a + (float) $r['a'];
$b = $b + (float) $r['b'];
$c = $c + (float) $r['c'];
$d = $d + (float) $r['d'];
$e = $e + (float) $r['e'];
$f = $f + (float) $r['f'];
$g = $g + (float) $r['g'];
}
$out .= "$a $b $c $d $e $f $g";
}
return $out;
}
Expected output
Analysis finishes in roughly the same time as on 2.2.17 (a few seconds), regardless of the number of accumulators.
Did PHPStan help you today? Did it make you happy in any way?
Very much: level 10 across a 3000-file legacy Yii2 project, and 2.3.1 is ~2.8× faster than 2.2.17 on the full project once this pattern is worked around. Thank you!
Environment: PHP 8.5.11, Linux, PHPStan 2.3.1 PHAR.
Activity
mergeable commentedon Oct 18, 2026
This bug report is missing a link to reproduction at phpstan.org/try.
It will most likely be closed after manual review.
mariusTestcard commentedon Oct 21, 2026
I get performance issues as well
ondrejmirtes commentedon Oct 21, 2026
@mariusTestcard Is it the same root cause? Can you confirm with: https://phpstan.org/blog/debugging-performance-identify-slow-files