*/ private array $interfaces = []; /** @var array> */ private array $implementations = []; /** @var array> */ private array $implementationsByClass = []; /** * @param array $targetInterfaces Die zu suchenden Interfaces */ public function __construct( private readonly array $targetInterfaces = [] ) { } public function onScanStart(): void { $this->implementations = []; $this->implementationsByClass = []; } public function onIncrementalScanStart(): void { // Bei inkrementellem Scan behalten wir vorhandene Implementierungen // und aktualisieren sie mit neuen Daten } public function onIncrementalScanComplete(): void { // Sortiere nach inkrementellem Scan $this->sortImplementations(); } public function visitClass(ClassName $className, FilePath $filePath): void { // This method is kept for backward compatibility but should not be used // when ReflectionProvider is available. The UnifiedDiscoveryService will // prefer visitClassWithReflection() when possible. } public function visitClassWithReflection(ClassName $className, FilePath $filePath, WrappedReflectionClass $reflection): void { try { // Skip abstract classes and interfaces - only process instantiable classes if (! $reflection->isInstantiable()) { return; } // Alte Einträge für diese Klasse entfernen (wichtig für inkrementelle Scans) $classNameStr = $className->getFullyQualified(); $this->removeImplementationsForClass($classNameStr); // Prüfe, ob die Klasse eines der Ziel-Interfaces implementiert foreach ($this->targetInterfaces as $interface) { if ($reflection->implementsInterface($interface)) { if (! isset($this->implementations[$interface])) { $this->implementations[$interface] = []; } // Prüfe auf Duplikate if (! in_array($classNameStr, $this->implementations[$interface])) { $this->implementations[$interface][] = $classNameStr; // Umgekehrten Index für schnelleren Zugriff aufbauen if (! isset($this->implementationsByClass[$classNameStr])) { $this->implementationsByClass[$classNameStr] = []; } $this->implementationsByClass[$classNameStr][] = $interface; } } } } catch (\Throwable $e) { // Silent failure - skip this class and continue with discovery } } /** * Entfernt alle Interface-Implementierungen für eine bestimmte Klasse */ private function removeImplementationsForClass(string $className): void { if (! isset($this->implementationsByClass[$className])) { return; } foreach ($this->implementationsByClass[$className] as $interface) { if (isset($this->implementations[$interface])) { $key = array_search($className, $this->implementations[$interface]); if ($key !== false) { unset($this->implementations[$interface][$key]); // Array-Indizes neu numerieren $this->implementations[$interface] = array_values($this->implementations[$interface]); } } } unset($this->implementationsByClass[$className]); } public function onScanComplete(): void { // Sortiere Implementierungen für konsistente Reihenfolge $this->sortImplementations(); } /** * Sortiert alle Implementierungen für konsistente Ergebnisse */ private function sortImplementations(): void { foreach ($this->implementations as &$classes) { sort($classes); } } public function loadFromCache(Cache $cache): void { $cacheItem = $cache->get($this->getCacheKey()); if ($cacheItem->isHit) { if (is_array($cacheItem->value) && isset($cacheItem->value['implementations'], $cacheItem->value['byClass'])) { $this->implementations = $cacheItem->value['implementations']; $this->implementationsByClass = $cacheItem->value['byClass']; } } } public function getCacheKey(): CacheKey { return CacheKey::fromString('interface_implementations'); } /** * @return array */ public function getCacheableData(): array { return [ 'implementations' => $this->implementations, 'byClass' => $this->implementationsByClass, ]; } /** * Gibt alle Implementierungen eines Interfaces zurück * @return array */ public function getImplementations(string $interface): array { return $this->implementations[$interface] ?? []; } /** * Prüft, ob eine Klasse ein bestimmtes Interface implementiert */ public function doesImplement(string $className, string $interface): bool { return isset($this->implementationsByClass[$className]) && in_array($interface, $this->implementationsByClass[$className]); } /** * Gibt alle Interfaces zurück, die eine Klasse implementiert * @return array */ public function getClassInterfaces(string $className): array { return $this->implementationsByClass[$className] ?? []; } /** * Gibt alle gefundenen Implementierungen zurück * @return array> */ public function getAllImplementations(): array { return $this->implementations; } }