From 972771ea42da066c8af3cc06c8d9abd22905f430 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Thu, 11 Jul 2024 14:40:43 +0900 Subject: [PATCH] Refactor Aspect class and update dependencies The Aspect class has been refactored for simplification and efficiency: the scanning and compilation process is now using a more performant approach by employing the package "wyrihaximus/list-classes-in-directory". Furthermore, usage of RecursiveDirectoryIterator and RecursiveIteratorIterator has been removed. The composer dependencies have been updated to reflect these changes. --- composer.json | 3 ++- src/Aspect.php | 47 +++++++++++------------------------------------ 2 files changed, 13 insertions(+), 37 deletions(-) diff --git a/composer.json b/composer.json index 490e70cc..9922c543 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ "ext-hash": "*", "ext-tokenizer": "*", "doctrine/annotations": "^1.12 || ^2.0", - "koriym/attributes": "^1.0.3" + "koriym/attributes": "^1.0.3", + "wyrihaximus/list-classes-in-directory": "^1.6" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", diff --git a/src/Aspect.php b/src/Aspect.php index 47c0fe7d..6c5547c7 100644 --- a/src/Aspect.php +++ b/src/Aspect.php @@ -4,8 +4,7 @@ namespace Ray\Aop; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; +use Ray\Aop\ReflectionMethod as RayAopReflectionMethod; use ReflectionClass; use ReflectionMethod; use RuntimeException; @@ -20,9 +19,11 @@ use function end; use function extension_loaded; use function get_declared_classes; +use function ksort; use function method_intercept; // @phpstan-ignore-line use function strcasecmp; use function sys_get_temp_dir; +use function WyriHaximus\listClassesInDirectories; final class Aspect { @@ -50,7 +51,7 @@ public function bind(AbstractMatcher $classMatcher, AbstractMatcher $methodMatch ]; } - public function weave(string $classDir): void + public function weave(string $classDir, ?callable $dispatcherFactory = null): void { if (! extension_loaded('rayaop')) { throw new RuntimeException('Ray.Aop extension is not loaded. Cannot use weave() method.'); @@ -62,18 +63,9 @@ public function weave(string $classDir): void private function scanAndCompile(string $classDir): void { - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($classDir) - ); - - /** @var SplFileInfo[] $files */ - foreach ($files as $file) { - if ($file->isDir() || $file->getExtension() !== 'php') { - continue; - } - - $className = $this->getClassNameFromFile($file->getPathname()); - if ($className === null) { + $classList = listClassesInDirectories($classDir); + foreach ($classList as $className) { + if (! class_exists($className)) { continue; } @@ -81,28 +73,9 @@ private function scanAndCompile(string $classDir): void } } - private function getClassNameFromFile(string $file): ?string - { - $declaredClasses = get_declared_classes(); - $previousCount = count($declaredClasses); - - /** @psalm-suppress UnresolvableInclude */ - require_once $file; - - $newClasses = array_slice(get_declared_classes(), $previousCount); - - foreach ($newClasses as $class) { - if (strcasecmp(basename($file, '.php'), $class) === 0) { - return $class; - } - } - - return $newClasses ? end($newClasses) : null; - } - private function processClass(string $className): void { - assert(class_exists($className)); + assert(class_exists($className), 'Class does not exist:' . $className); $reflection = new ReflectionClass($className); foreach ($this->matchers as $matcher) { @@ -111,7 +84,8 @@ private function processClass(string $className): void } foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { - if (! $matcher['methodMatcher']->matchesMethod($method, $matcher['methodMatcher']->getArguments())) { + $aopMethod = new RayAopReflectionMethod($className, $method->getName()); + if (! $matcher['methodMatcher']->matchesMethod($aopMethod, $matcher['methodMatcher']->getArguments())) { continue; } @@ -127,6 +101,7 @@ private function applyInterceptors(): void } $dispatcher = new PeclDispatcher($this->bound); + ksort($this->bound); foreach ($this->bound as $className => $methods) { $methodNames = array_keys($methods); foreach ($methodNames as $methodName) {