Conversation
A type alias referenced by many keys of an array shape is one shared Type object. `MissingTypehintCheck::getIterableTypesWithMissingValueTypehint()` walked that object again for every key referring to it, and for every constant array it met it also ran a second full walk to drop its unsealed part. The array shape that symfony/ux-css generates for its `css()` Twig function has about 840 keys, 126 of them referring to a nested shape, and checking one method parameter against it took seconds. The callback only depends on the type it's given, so each object is now checked once. Later visits of the same object replay the descriptions added during the first visit, in the same order, so reported errors don't change, duplicates included. The inner walk that drops unsealed parts caches its result per object the same way. Objects are keyed with `spl_object_id()` and kept in the cache for the duration of the walk, so an id can't be reused in between. | Scenario | Before | After | |---|---|---| | New `nested-array-shape-alias.php` bench | 117.4-117.9 ms | 70.4-70.7 ms | | Real ux-css shape, 2 levels, 1 call, turbo extension loaded | 5.37-5.41 s | 4.41-4.43 s | The rest of the phpbench suite stays within its existing thresholds. The two scenarios with the largest difference, bug-7140 and bug-8503, were re-run 3 times with 15 iterations each, and the difference turned out to be noise (22.40-22.57 ms vs 22.41-22.49 ms, and 123.9-125.6 ms vs 122.9-127.1 ms). ``` XDEBUG_MODE=off tests/vendor/bin/phpbench run --variant=nested-array-shape-alias.php --iterations=10 --report=aggregate ```
how to reproduce this workload, so we can look into why this takes 5 seconds as a whole? |
Oh you're right, I'm creating a reproducer |
|
@staabm I just opened https://github.com/Kocal/sf-ux-css-phpstan-reproducer |
|
I took some profiles and put the information into a issue: phpstan/phpstan#15348 |
|
@Kocal in my measures running the slow snippet on 2.2.16 will be waaaaay faster on 2.3.x, see phpstan/phpstan#15348 |
|
Ooooh awesome, thanks for investigating that much! :D I saw that you opened some PRs, let me know if this one become useless |
|
yeah, I think we can close here. we found a more general approach which will impact even more use-case. thanks for the nice reproducer, its really helpful. |
A type alias referenced by many keys of an array shape is one shared Type object.
MissingTypehintCheck::getIterableTypesWithMissingValueTypehint()walked that object again for every key referring to it, and for every constant array it met it also ran a second full walk to drop its unsealed part.The array shape that symfony/ux-css generates for its
css()Twig function has about 840 keys, 126 of them referring to a nested shape, and checking one method parameter against it took seconds.The callback only depends on the type it's given, so each object is now checked once. Later visits of the same object replay the descriptions added during the first visit, in the same order, so reported errors don't change, duplicates included. The inner walk that drops unsealed parts caches its result per object the same way. Objects are keyed with
spl_object_id()and kept in the cache for the duration of the walk, so an id can't be reused in between.nested-array-shape-alias.phpbenchThe rest of the phpbench suite stays within its existing thresholds. The two scenarios with the largest difference, bug-7140 and bug-8503, were re-run 3 times with 15 iterations each, and the difference turned out to be noise (22.40-22.57 ms vs 22.41-22.49 ms, and 123.9-125.6 ms vs 122.9-127.1 ms).