diff --git a/src/Reflection/CHANGELOG.md b/src/Reflection/CHANGELOG.md index ebf6ee4e..fd05671a 100644 --- a/src/Reflection/CHANGELOG.md +++ b/src/Reflection/CHANGELOG.md @@ -9,3 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Implemented `getType()`, `getReturnType()`, `getTentativeReturnType()`, `hasTentativeReturnType()`, `hasReturnType()`. - Deprecated `FileResource::changeDetector()`. +- Introduced new parameter `TyphoonReflector::build($fallbackToNativeReflection = true)`. +- Deprecated `NativeReflectionFileLocator`. +- Deprecated `NativeReflectionLocator`. +- Deprecated returning `ReflectionClass` from `ClassLocator::locateClass()`. diff --git a/src/Reflection/ClassLocator/NativeReflectionFileLocator.php b/src/Reflection/ClassLocator/NativeReflectionFileLocator.php index fe4b57a2..8ca3f081 100644 --- a/src/Reflection/ClassLocator/NativeReflectionFileLocator.php +++ b/src/Reflection/ClassLocator/NativeReflectionFileLocator.php @@ -9,6 +9,7 @@ /** * @api + * @deprecated use TyphoonReflector::build($fallbackToNativeReflection) instead */ final class NativeReflectionFileLocator implements ClassLocator { diff --git a/src/Reflection/ClassLocator/NativeReflectionLocator.php b/src/Reflection/ClassLocator/NativeReflectionLocator.php index 84f71620..aeb436f1 100644 --- a/src/Reflection/ClassLocator/NativeReflectionLocator.php +++ b/src/Reflection/ClassLocator/NativeReflectionLocator.php @@ -8,6 +8,7 @@ /** * @api + * @deprecated use TyphoonReflector::build($fallbackToNativeReflection) instead */ final class NativeReflectionLocator implements ClassLocator { diff --git a/src/Reflection/TyphoonReflector.php b/src/Reflection/TyphoonReflector.php index 7adad465..675ee1f1 100644 --- a/src/Reflection/TyphoonReflector.php +++ b/src/Reflection/TyphoonReflector.php @@ -10,8 +10,6 @@ use Typhoon\Reflection\Cache\InMemoryCache; use Typhoon\Reflection\ClassLocator\ClassLocators; use Typhoon\Reflection\ClassLocator\ComposerClassLocator; -use Typhoon\Reflection\ClassLocator\NativeReflectionFileLocator; -use Typhoon\Reflection\ClassLocator\NativeReflectionLocator; use Typhoon\Reflection\ClassLocator\PhpStormStubsClassLocator; use Typhoon\Reflection\ClassReflection\ClassReflector; use Typhoon\Reflection\Exception\ClassDoesNotExist; @@ -36,6 +34,7 @@ private function __construct( private readonly NativeReflector $nativeReflector, private readonly ClassLocator $classLocator, private readonly MetadataStorage $metadataStorage, + private readonly bool $fallbackToNativeReflection, ) {} public static function build( @@ -43,6 +42,7 @@ public static function build( CacheInterface $cache = new InMemoryCache(), TagPrioritizer $tagPrioritizer = new PrefixBasedTagPrioritizer(), ?PhpParser $phpParser = null, + bool $fallbackToNativeReflection = true, ): self { return new self( phpParserReflector: new PhpParserReflector( @@ -52,6 +52,7 @@ public static function build( nativeReflector: new NativeReflector(), classLocator: $classLocator ?? self::defaultClassLocator(), metadataStorage: new MetadataStorage($cache), + fallbackToNativeReflection: $fallbackToNativeReflection, ); } @@ -67,9 +68,6 @@ public static function defaultClassLocator(): ClassLocator $classLocators[] = new ComposerClassLocator(); } - $classLocators[] = new NativeReflectionFileLocator(); - $classLocators[] = new NativeReflectionLocator(); - return new ClassLocators($classLocators); } @@ -139,20 +137,62 @@ private function reflectClassMetadata(string $name): ClassMetadata return $metadata; } - $location = $this->classLocator->locateClass($name) - ?? throw new ClassDoesNotExist($name); + $resource = $this->locateClass($name); - if ($location instanceof \ReflectionClass) { - $metadata = $this->nativeReflector->reflectClass($location); + if ($resource instanceof \ReflectionClass) { + $metadata = $this->nativeReflector->reflectClass($resource); $this->metadataStorage->save($metadata); return $metadata; } - $this->phpParserReflector->reflectFile($location, new WeakClassExistenceChecker($this), $this->metadataStorage); + $this->phpParserReflector->reflectFile($resource, new WeakClassExistenceChecker($this), $this->metadataStorage); $metadata = $this->metadataStorage->get(ClassMetadata::class, $name); $this->metadataStorage->commit(); return $metadata ?? throw new ClassDoesNotExist($name); } + + /** + * @param non-empty-string $name + */ + private function locateClass(string $name): FileResource|\ReflectionClass + { + $resource = $this->classLocator->locateClass($name); + + if ($resource instanceof FileResource) { + return $resource; + } + + if ($resource instanceof \ReflectionClass) { + trigger_deprecation( + 'typhoon/reflection', + '0.3.1', + 'Returning %s from %s is deprecated, use %s::build($fallbackToNativeReflection) instead.', + \ReflectionClass::class, + ClassLocator::class, + self::class, + ); + + return $resource; + } + + if (!$this->fallbackToNativeReflection) { + throw new ClassDoesNotExist($name); + } + + try { + $reflectionClass = new \ReflectionClass($name); + } catch (\ReflectionException) { + throw new ClassDoesNotExist($name); + } + + $file = $reflectionClass->getFileName(); + + if ($file !== false) { + return new FileResource($file, $reflectionClass->getExtensionName()); + } + + return $reflectionClass; + } } diff --git a/tests/Reflection/ReflectorCompatibilityTest.php b/tests/Reflection/ReflectorCompatibilityTest.php index cab64240..61f62577 100644 --- a/tests/Reflection/ReflectorCompatibilityTest.php +++ b/tests/Reflection/ReflectorCompatibilityTest.php @@ -9,7 +9,7 @@ use PHPUnit\Framework\Attributes\DataProviderExternal; use PHPUnit\Framework\TestCase; use Traits\Trait1; -use Typhoon\Reflection\ClassLocator\NativeReflectionLocator; +use Typhoon\Reflection\ClassLocator\ClassLocators; use Typhoon\Type\Variance; #[CoversClass(AttributeReflection::class)] @@ -28,7 +28,7 @@ public static function setUpBeforeClass(): void { \Mockery::setLoader(new RequireLoader(__DIR__ . '/../../var/mockery')); self::$defaultReflector = TyphoonReflector::build(); - self::$nativeReflector = TyphoonReflector::build(new NativeReflectionLocator()); + self::$nativeReflector = TyphoonReflector::build(new ClassLocators([])); } /**