Skip to content

refactor: offload plugin discovery to PluginDiscovery class#45

Merged
markshust merged 3 commits into
marko-php:developfrom
iamlasse:feature/plugin-discovery-cleanup
May 1, 2026
Merged

refactor: offload plugin discovery to PluginDiscovery class#45
markshust merged 3 commits into
marko-php:developfrom
iamlasse:feature/plugin-discovery-cleanup

Conversation

@iamlasse
Copy link
Copy Markdown
Contributor

@iamlasse iamlasse commented Apr 29, 2026

What

Offloads plugin discovery logic into PluginDiscovery so Application doesn't duplicate the work. Follow-up to #44.

Also drops the ClassFileParser constructor injection that #44 introduced on PreferenceDiscovery — see "Constructor cleanup" below.

Changes

  • PluginDiscovery::discoverInModule() returns PluginDefinition[] (already-parsed) instead of raw file paths.
  • Extraction + loadClass + reflection moves out of Application::discoverPlugins() into PluginDiscovery.
  • PluginDiscovery keeps the cheap str_contains('#[Plugin') pre-filter so non-plugin files don't pay for extraction + autoload + reflection.
  • Application::discoverPlugins() simplified to iterate definitions and register.

Constructor cleanup

PluginDiscovery and PreferenceDiscovery no longer take ClassFileParser via constructor — they new one internally. The parser is a stateless utility class with one implementation that's never mocked, so the injection was ceremony: tests had to construct a parser inline just to satisfy the signature. Removing it cuts test boilerplate and avoids a public-API break for anyone who was instantiating these directly.

Application no longer threads $this->classFileParser through to either discovery class. The property remains for CommandDiscovery, which still uses it.

@github-actions github-actions Bot added the refactor Code refactoring with no behavior change label Apr 29, 2026
- PluginDiscovery::discoverInModule() now returns PluginDefinition[]
  instead of raw file paths, eliminating duplicate extract/load/reflect
  work in Application
- Requires ClassFileParser via constructor (no default instantiation)
- Uses ClassFileParser for file scanning instead of its own
  RecursiveDirectoryIterator + RegexIterator
- Application::discoverPlugins() simplified to iterate definitions
  and register
@iamlasse iamlasse force-pushed the feature/plugin-discovery-cleanup branch from 279e2ad to cf989f4 Compare April 29, 2026 17:01
markshust and others added 2 commits May 1, 2026 13:47
Plugin/PreferenceDiscovery were taking ClassFileParser through their
constructors, but the parser is a stateless utility with one implementation
that's never mocked. Constructor injection here was ceremony — every test
had to construct a real ClassFileParser inline just to satisfy the signature.

Both classes now `new ClassFileParser()` once inside discoverInModule().
Application no longer threads $this->classFileParser through to either
discovery class. Restored the str_contains pre-filter in PluginDiscovery so
non-plugin files don't pay for extractClassName + loadClass + reflection.
Dropped the redundant class_exists() check after loadClass() (already
guaranteed). For consistency, applied the same cleanup to PreferenceDiscovery
that was the subject of the prior refactor in marko-php#44.

Co-Authored-By: Lasse Larsen <iamlasse@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added refactor Code refactoring with no behavior change and removed refactor Code refactoring with no behavior change labels May 1, 2026
@markshust
Copy link
Copy Markdown
Collaborator

Thanks again @iamlasse — clean, well-framed PR this time, and the structural intent matches the follow-up I'd called out in #44. Pushed a follow-up commit (c61277f) and updated the PR body. Summary:

Kept and validated

  • Refactor moving extraction/loadClass/reflection from Application::discoverPlugins() into PluginDiscovery. PluginDiscovery::discoverInModule() now returns PluginDefinition[] ready for registration.
  • Application import cleanup follows naturally (Plugin, ReflectionClass no longer needed there).

Adjusted

  • Restored the str_contains('#[Plugin') content pre-filter. Same perf concern as refactor: preference discovery and class extraction logic #44 — without it, every .php file in every module's src/ was paying for extractClassName + loadClass + ReflectionClass on each boot. The pre-filter is a cheap file read that lets non-plugin files short-circuit before the expensive work.
  • Dropped the redundant class_exists($className) check after loadClass(). ClassFileParser::loadClass() already guarantees the class is loaded before returning true.

Constructor cleanup (and consistency with #44)
Dropped the ClassFileParser constructor injection from both PluginDiscovery and PreferenceDiscovery. Both now new ClassFileParser() internally. Reasoning: the parser is a stateless utility with one implementation that's never mocked — every test had to construct one inline just to satisfy the signature. Removing it cuts test boilerplate (~13 inline parser constructions in PluginDiscoveryTest) and avoids a backwards-incompatible API change for anyone who was instantiating these directly.

Application no longer threads $this->classFileParser through to either discovery class — the property stays for CommandDiscovery, which still uses it.

Tests pass (4845), lint clean. Ready to merge.

@markshust markshust merged commit 217cde0 into marko-php:develop May 1, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Code refactoring with no behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants