1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace PHPStan\BetterReflection\SourceLocator\Type;
6:
7: use InvalidArgumentException;
8: use ReflectionClass as CoreReflectionClass;
9: use PHPStan\BetterReflection\Identifier\Identifier;
10: use PHPStan\BetterReflection\SourceLocator\Ast\Locator;
11: use PHPStan\BetterReflection\SourceLocator\Exception\InvalidFileLocation;
12: use PHPStan\BetterReflection\SourceLocator\Located\InternalLocatedSource;
13: use PHPStan\BetterReflection\SourceLocator\Located\LocatedSource;
14: use PHPStan\BetterReflection\SourceLocator\SourceStubber\SourceStubber;
15: use PHPStan\BetterReflection\SourceLocator\SourceStubber\StubData;
16:
17: use function class_exists;
18: use function strtolower;
19:
20: final class PhpInternalSourceLocator extends AbstractSourceLocator
21: {
22: private SourceStubber $stubber;
23: public function __construct(Locator $astLocator, SourceStubber $stubber)
24: {
25: $this->stubber = $stubber;
26: parent::__construct($astLocator);
27: }
28:
29: /**
30: * {@inheritDoc}
31: *
32: * @throws InvalidArgumentException
33: * @throws InvalidFileLocation
34: */
35: protected function createLocatedSource(Identifier $identifier): ?\PHPStan\BetterReflection\SourceLocator\Located\LocatedSource
36: {
37: return $this->getClassSource($identifier)
38: ?? $this->getFunctionSource($identifier)
39: ?? $this->getConstantSource($identifier);
40: }
41:
42: private function getClassSource(Identifier $identifier): ?\PHPStan\BetterReflection\SourceLocator\Located\InternalLocatedSource
43: {
44: if (! $identifier->isClass()) {
45: return null;
46: }
47:
48: /** @psalm-var class-string|trait-string $className */
49: $className = $identifier->getName();
50: $aliasName = null;
51:
52: if (class_exists($className, false)) {
53: $reflectionClass = new CoreReflectionClass($className);
54:
55: if (strtolower($reflectionClass->getName()) !== strtolower($className)) {
56: $aliasName = $className;
57: $className = $reflectionClass->getName();
58: $identifier = new Identifier($className, $identifier->getType());
59: }
60: }
61:
62: return $this->createLocatedSourceFromStubData($identifier, $this->stubber->generateClassStub($className), $aliasName);
63: }
64:
65: private function getFunctionSource(Identifier $identifier): ?\PHPStan\BetterReflection\SourceLocator\Located\InternalLocatedSource
66: {
67: if (! $identifier->isFunction()) {
68: return null;
69: }
70:
71: return $this->createLocatedSourceFromStubData($identifier, $this->stubber->generateFunctionStub($identifier->getName()));
72: }
73:
74: private function getConstantSource(Identifier $identifier): ?\PHPStan\BetterReflection\SourceLocator\Located\InternalLocatedSource
75: {
76: if (! $identifier->isConstant()) {
77: return null;
78: }
79:
80: return $this->createLocatedSourceFromStubData($identifier, $this->stubber->generateConstantStub($identifier->getName()));
81: }
82:
83: private function createLocatedSourceFromStubData(Identifier $identifier, ?\PHPStan\BetterReflection\SourceLocator\SourceStubber\StubData $stubData, ?string $aliasName = null): ?\PHPStan\BetterReflection\SourceLocator\Located\InternalLocatedSource
84: {
85: if ($stubData === null) {
86: return null;
87: }
88:
89: $extensionName = $stubData->getExtensionName();
90:
91: if ($extensionName === null) {
92: // Not internal
93: return null;
94: }
95:
96: return new InternalLocatedSource(
97: $stubData->getStub(),
98: $identifier->getName(),
99: $extensionName,
100: $stubData->getFileName(),
101: $aliasName,
102: );
103: }
104: }
105: