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: /** @psalm-var class-string|trait-string $className */
58: $className = $reflectionClass->getName();
59: $identifier = new Identifier($className, $identifier->getType());
60: }
61: }
62:
63: return $this->createLocatedSourceFromStubData($identifier, $this->stubber->generateClassStub($className), $aliasName);
64: }
65:
66: private function getFunctionSource(Identifier $identifier): ?\PHPStan\BetterReflection\SourceLocator\Located\InternalLocatedSource
67: {
68: if (! $identifier->isFunction()) {
69: return null;
70: }
71:
72: return $this->createLocatedSourceFromStubData($identifier, $this->stubber->generateFunctionStub($identifier->getName()));
73: }
74:
75: private function getConstantSource(Identifier $identifier): ?\PHPStan\BetterReflection\SourceLocator\Located\InternalLocatedSource
76: {
77: if (! $identifier->isConstant()) {
78: return null;
79: }
80:
81: return $this->createLocatedSourceFromStubData($identifier, $this->stubber->generateConstantStub($identifier->getName()));
82: }
83:
84: private function createLocatedSourceFromStubData(Identifier $identifier, ?\PHPStan\BetterReflection\SourceLocator\SourceStubber\StubData $stubData, ?string $aliasName = null): ?\PHPStan\BetterReflection\SourceLocator\Located\InternalLocatedSource
85: {
86: if ($stubData === null) {
87: return null;
88: }
89:
90: $extensionName = $stubData->getExtensionName();
91:
92: if ($extensionName === null) {
93: // Not internal
94: return null;
95: }
96:
97: return new InternalLocatedSource(
98: $stubData->getStub(),
99: $identifier->getName(),
100: $extensionName,
101: $stubData->getFileName(),
102: $aliasName,
103: );
104: }
105: }
106: