<?phpdeclare(strict_types=1);namespace Csoft\AutoInvoker\ClassFinder;use Csoft\AutoInvoker\AutoInvokeRule\AutoInvokeRuleInterface;use Generator;use ReflectionClass;use ReflectionException;use Symfony\Component\Finder\Finder;class ClassFinder implements ClassFinderInterface{ /** @var array */ protected $classes; /** * @inheritDoc */ public function getMatchingClasses(AutoInvokeRuleInterface $rule): array { // Preloads the available classes for the rule. $this->fetchClasses($rule); $matchingClasses = []; foreach ($rule->getSourcePaths() as $path) { foreach ($this->classes[$path] as $fqn => $interfaces) { // If the rule presents all class or we matched the class. if ($rule->getInvokableInterface() === '' || in_array( $rule->getInvokableInterface(), $interfaces, true )) { $matchingClasses[] = $fqn; } } } return $matchingClasses; } /** * Fetches all available and autoloadable classes from the given paths. * * @param AutoInvokeRuleInterface $rule */ protected function fetchClasses(AutoInvokeRuleInterface $rule) { foreach ($rule->getSourcePaths() as $path) { if (empty($this->classes[$path])) { $this->classes[$path] = []; foreach ($this->fetchClassesFromPath($path) as $fqn => $interfaces) { $this->classes[$path][$fqn] = $interfaces; } } } } /** * Fetches all available and autoloadable classes from the given path. * * @param string $path * * @return Generator */ protected function fetchClassesFromPath(string $path): Generator { foreach ($this->getFinder()->files()->name('*.php')->in($path) as $file) { foreach ($this->fetchClassesFromContent($file->getContents()) as $fqn => $interfaces) { yield $fqn => $interfaces; } } } /** * Returns a Finder instance. * * @return Finder */ protected function getFinder(): Finder { return new Finder(); } /** * Fetches all available and autoloadable classes from the given content. * * @param string $content * * @return Generator */ protected function fetchClassesFromContent(string $content): Generator { $namespace = ClassParser::getNameSpaceFromContent($content); $className = ClassParser::getClassNameFromContent($content); if (empty($className) === false) { foreach ($className as $currentClassName) { $fqn = $namespace . '\\' . $currentClassName; try { $reflectionClass = new ReflectionClass($fqn); if ($reflectionClass->isAbstract() === false) { yield $fqn => $reflectionClass->getInterfaceNames(); } } catch (ReflectionException $e) { //echo $e->getMessage() . PHP_EOL; } } } }}