🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

Drop the container reference in LazyClassReflectionExtensionRegistryProvider after building the registry - #5985

Merged
ondrejmirtes merged 1 commit into
2.2.xfrom
lazy-registry-provider-drop-container-ref
Jul 3, 2026
Merged

Drop the container reference in LazyClassReflectionExtensionRegistryProvider after building the registry#5985
ondrejmirtes merged 1 commit into
2.2.xfrom
lazy-registry-provider-drop-container-ref

Conversation

@ondrejmirtes

Copy link
Copy Markdown
Member

Every ClassReflection instance holds ClassReflectionExtensionRegistryProvider as a constructor dependency (ClassReflection.php), and the lazy provider kept its Container reference for the whole process — making every ClassReflection (and transitively every ObjectType that ever lazily resolved its class, every ResolvedPhpDocBlock tag type, every cached signature) a handle on the entire DI container.

The reference is only needed once, to build the registry on first use. This PR nulls it out afterwards.

Found while instrumenting memory retention on a large project (ShipMonk backend): retention-path tracing repeatedly showed ... → ObjectType::$classReflection → ClassReflection::$classReflectionExtensionRegistryProvider → LazyClassReflectionExtensionRegistryProvider::$container → Container::$instances[] → everything, which (a) means a single stale reflection can keep a whole dead container alive (e.g. the stub validator's derived container, #5984), and (b) defeats any future eviction strategy for class reflections. After this change the instrumentation confirms no reference chain from ClassReflection to the container remains.

No behavioral change; ClassReflectionTest, ClassTemplateTypeRuleTest, StubValidatorIntegrationTest pass, phpcs clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NrTvR9j1mW2NNNC8RkuTsF

…rovider after building the registry

Every ClassReflection instance holds this provider as a constructor
dependency. Because the provider kept its Container reference for the whole
process, every ClassReflection — and transitively every ObjectType that ever
resolved its class, every ResolvedPhpDocBlock tag type, every cached
signature — was a handle on the entire DI container.

That reference is only needed once, to build the registry lazily. Null it out
afterwards. Verified with retention-path instrumentation on a large project:
no reference chain from ClassReflection to the container remains, which is a
prerequisite for any future eviction of class reflections to actually free
memory (and prevents a stale reflection from keeping a dead container alive,
e.g. after stub validation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NrTvR9j1mW2NNNC8RkuTsF
@ondrejmirtes
ondrejmirtes merged commit 5a1c8cd into 2.2.x Jul 3, 2026
668 of 670 checks passed
@ondrejmirtes
ondrejmirtes deleted the lazy-registry-provider-drop-container-ref branch July 3, 2026 11:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant