Commit 1d886b3
committed
[LiveComponent] Cache the attribute-method lookups per component class
| Q | A
| -------------- | ---
| Bug fix? | no
| New feature? | no
| Deprecations? | no
| Documentation? | no
| Issues | -
| License | MIT
`liveListeners()`, `preDehydrateMethods()`, `postHydrateMethods()`,
`preReRenderMethods()` and `isActionAllowed()` each rebuild a
`ReflectionClass` and walk every public method of the component, on every
render and every request. What they return only depends on the component
class.
Memoize the resolved methods per class and attribute. An earlier revision of
this branch put the cache in `AsTwigComponent`, where those helpers live, but
they have no other consumer than `AsLiveComponent`, so the cache belongs here
and TwigComponent is left untouched.
Timings use the call counts from the review: a page holding five
LiveComponents calls `liveListeners()` and `preDehydrateMethods()` once per
component on the initial render, and a single component update calls each of
the five once.
initial render, 5 components 18.1 us -> 2.9 us
one component update 8.2 us -> 1.0 us
Sixteen microseconds off a page render is not going to show up in a profile;
the ratio is what it is because reflection is simply not needed more than
once per class.
Benchmarked from the repository root with `symfony php bench.php`:
```php
<?php
require __DIR__.'/src/LiveComponent/vendor/autoload.php';
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveListener;
use Symfony\UX\LiveComponent\Attribute\PostHydrate;
use Symfony\UX\LiveComponent\Attribute\PreDehydrate;
use Symfony\UX\LiveComponent\Attribute\PreReRender;
#[AsLiveComponent('Bench')]
class BenchComponent
{
#[PreDehydrate] public function onPreDehydrate() {}
#[PostHydrate] public function onPostHydrate() {}
#[PreReRender] public function onPreReRender() {}
#[LiveAction] public function save() {}
#[LiveListener('foo:bar')] public function onFooBar() {}
public function noise1() {} public function noise2() {} public function noise3() {}
public function noise4() {} public function noise5() {} public function noise6() {}
}
$component = new BenchComponent();
$render = static function () use ($component) {
for ($i = 0; $i < 5; ++$i) {
AsLiveComponent::liveListeners($component);
AsLiveComponent::preDehydrateMethods($component);
}
};
$update = static function () use ($component) {
AsLiveComponent::liveListeners($component);
AsLiveComponent::preDehydrateMethods($component);
AsLiveComponent::postHydrateMethods($component);
AsLiveComponent::preReRenderMethods($component);
AsLiveComponent::isActionAllowed($component, 'save');
};
foreach (['initial render' => $render, 'one update' => $update] as $label => $fn) {
$fn();
$start = hrtime(true);
for ($i = 0; $i < 2000; ++$i) { $fn(); }
printf("%-16s %6.1f us\n", $label, (hrtime(true) - $start) / 1e3 / 2000);
}
```
Analysis, implementation and benchmarks by Claude Opus 5.1 parent 26a3746 commit 1d886b3
1 file changed
Lines changed: 36 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
28 | 33 | | |
29 | 34 | | |
30 | 35 | | |
| |||
93 | 98 | | |
94 | 99 | | |
95 | 100 | | |
96 | | - | |
| 101 | + | |
97 | 102 | | |
98 | 103 | | |
99 | 104 | | |
| |||
111 | 116 | | |
112 | 117 | | |
113 | 118 | | |
114 | | - | |
| 119 | + | |
115 | 120 | | |
116 | 121 | | |
117 | 122 | | |
| |||
123 | 128 | | |
124 | 129 | | |
125 | 130 | | |
126 | | - | |
| 131 | + | |
127 | 132 | | |
128 | 133 | | |
129 | 134 | | |
| |||
135 | 140 | | |
136 | 141 | | |
137 | 142 | | |
138 | | - | |
| 143 | + | |
139 | 144 | | |
140 | 145 | | |
141 | 146 | | |
| |||
148 | 153 | | |
149 | 154 | | |
150 | 155 | | |
151 | | - | |
| 156 | + | |
152 | 157 | | |
153 | 158 | | |
154 | 159 | | |
155 | 160 | | |
156 | 161 | | |
157 | 162 | | |
158 | 163 | | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
159 | 190 | | |
0 commit comments