Skip to content

perf: cache ReflectionClass calls in isPhpCoreClass#607

Merged
fain182 merged 3 commits intomainfrom
perf/isphpcoreclass-cache
Apr 5, 2026
Merged

perf: cache ReflectionClass calls in isPhpCoreClass#607
fain182 merged 3 commits intomainfrom
perf/isphpcoreclass-cache

Conversation

@fain182
Copy link
Copy Markdown
Collaborator

@fain182 fain182 commented Apr 4, 2026

Closes #580

Problem

isPhpCoreClass() in ClassDescriptionBuilder calls new ReflectionClass() for every dependency of every analyzed class, with no caching. This was identified in #580 as the source of a measurable performance regression introduced after v0.8.0.

On arkitect's own 104-file codebase, ReflectionClass was being instantiated 849 times — many of those for the same class names repeated across files, and many more for user-land classes that don't even exist in the current process (triggering exception handling as control flow).

Changes

  • Cache: results are stored in a static array keyed by FQCN. Subsequent calls for the same class name return immediately without any reflection.
  • Early exit: if the class is not loaded in the current process (class_exists / interface_exists), it cannot be a PHP internal class — return false immediately, skipping ReflectionClass entirely.
  • Removed try/catch: now that we guard with class_exists first, ReflectionClass will never throw for the classes that reach it, so exception-as-control-flow is gone.
  • Extracted checkIsPhpCoreClass: cache logic and detection logic are now in separate methods.

Results

Measured on arkitect's own codebase (104 files):

ReflectionClass calls
Before 849
After 148
Reduction -83%

🤖 Generated with Claude Code

Avoid repeated ReflectionClass instantiation for the same FQCN by
caching results in a static array. Also skip reflection entirely for
classes not loaded in the current process, as they cannot be internal.

Reduces ReflectionClass calls from 849 to 148 on arkitect's own codebase
(104 files).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.32%. Comparing base (9092a4c) to head (e9df60e).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##               main     #607   +/-   ##
=========================================
  Coverage     98.32%   98.32%           
- Complexity      684      689    +5     
=========================================
  Files            86       86           
  Lines          1965     1968    +3     
=========================================
+ Hits           1932     1935    +3     
  Misses           33       33           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@fain182 fain182 requested a review from micheleorselli April 4, 2026 16:34
Copy link
Copy Markdown
Member

@micheleorselli micheleorselli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left one comment on the check condition. Apart from that this seems to me a quick win to improve the current situation so 👍

…PhpCoreClass

Extends the "not loaded = not core" fast path to traits and enums,
avoiding unnecessary ReflectionClass instantiations for unloaded symbols.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@fain182 fain182 merged commit ff6389b into main Apr 5, 2026
35 checks passed
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.

isPhpCoreClass() is causing significant performance overhead

2 participants