1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace PHPStan\BetterReflection;
6:
7: use PhpParser\Parser;
8: use PhpParser\ParserFactory;
9: use PhpParser\PrettyPrinter\Standard;
10: use PHPStan\BetterReflection\Reflector\DefaultReflector;
11: use PHPStan\BetterReflection\Reflector\Reflector;
12: use PHPStan\BetterReflection\SourceLocator\Ast\Locator as AstLocator;
13: use PHPStan\BetterReflection\SourceLocator\SourceStubber\AggregateSourceStubber;
14: use PHPStan\BetterReflection\SourceLocator\SourceStubber\PhpStormStubsSourceStubber;
15: use PHPStan\BetterReflection\SourceLocator\SourceStubber\ReflectionSourceStubber;
16: use PHPStan\BetterReflection\SourceLocator\SourceStubber\SourceStubber;
17: use PHPStan\BetterReflection\SourceLocator\Type\AggregateSourceLocator;
18: use PHPStan\BetterReflection\SourceLocator\Type\AutoloadSourceLocator;
19: use PHPStan\BetterReflection\SourceLocator\Type\EvaledCodeSourceLocator;
20: use PHPStan\BetterReflection\SourceLocator\Type\MemoizingSourceLocator;
21: use PHPStan\BetterReflection\SourceLocator\Type\PhpInternalSourceLocator;
22: use PHPStan\BetterReflection\SourceLocator\Type\SourceLocator;
23: use PHPStan\BetterReflection\Util\FindReflectionOnLine;
24:
25: use const PHP_VERSION_ID;
26:
27: final class BetterReflection
28: {
29: public static int $phpVersion = PHP_VERSION_ID;
30:
31: /**
32: * @var \PHPStan\BetterReflection\SourceLocator\Type\SourceLocator|null
33: */
34: private static $sharedSourceLocator = null;
35:
36: /**
37: * @var \PHPStan\BetterReflection\SourceLocator\Type\SourceLocator|null
38: */
39: private $sourceLocator = null;
40:
41: /**
42: * @var \PHPStan\BetterReflection\Reflector\Reflector|null
43: */
44: private static $sharedReflector = null;
45:
46: /**
47: * @var \PHPStan\BetterReflection\Reflector\Reflector|null
48: */
49: private $reflector = null;
50:
51: /**
52: * @var \PhpParser\Parser|null
53: */
54: private static $sharedPhpParser = null;
55:
56: /**
57: * @var \PhpParser\Parser|null
58: */
59: private $phpParser = null;
60:
61: /**
62: * @var \PhpParser\Parser|null
63: */
64: private $originalPhpParser = null;
65:
66: /**
67: * @var AstLocator|null
68: */
69: private $astLocator = null;
70:
71: /**
72: * @var \PHPStan\BetterReflection\Util\FindReflectionOnLine|null
73: */
74: private $findReflectionOnLine = null;
75:
76: /**
77: * @var \PHPStan\BetterReflection\SourceLocator\SourceStubber\SourceStubber|null
78: */
79: private $sourceStubber = null;
80:
81: /**
82: * @var \PHPStan\BetterReflection\SourceLocator\SourceStubber\SourceStubber|null
83: */
84: private static $sharedSourceStubber = null;
85:
86: /**
87: * @var Standard|null
88: */
89: private static $sharedPrinter = null;
90:
91: /**
92: * @var Standard|null
93: */
94: private $printer = null;
95:
96: public static function populate(
97: int $phpVersion,
98: SourceLocator $sourceLocator,
99: Reflector $classReflector,
100: Parser $phpParser,
101: SourceStubber $sourceStubber,
102: Standard $printer
103: ): void {
104: self::$phpVersion = $phpVersion;
105: self::$sharedSourceLocator = $sourceLocator;
106: self::$sharedReflector = $classReflector;
107: self::$sharedPhpParser = $phpParser;
108: self::$sharedSourceStubber = $sourceStubber;
109: self::$sharedPrinter = $printer;
110: }
111:
112: public function __construct()
113: {
114: $this->sourceLocator = self::$sharedSourceLocator;
115: $this->reflector = self::$sharedReflector;
116: $this->phpParser = self::$sharedPhpParser;
117: $this->sourceStubber = self::$sharedSourceStubber;
118: $this->printer = self::$sharedPrinter;
119: }
120:
121: public function sourceLocator(): SourceLocator
122: {
123: $astLocator = $this->astLocator();
124: $sourceStubber = $this->sourceStubber();
125:
126: return $this->sourceLocator
127: ?? $this->sourceLocator = new MemoizingSourceLocator(new AggregateSourceLocator([
128: new PhpInternalSourceLocator($astLocator, $sourceStubber),
129: new EvaledCodeSourceLocator($astLocator, $sourceStubber),
130: new AutoloadSourceLocator($astLocator, $this->phpParser()),
131: ]));
132: }
133:
134: public function reflector(): Reflector
135: {
136: return $this->reflector
137: ?? $this->reflector = new DefaultReflector($this->sourceLocator());
138: }
139:
140: public function phpParser(): Parser
141: {
142: return $this->phpParser
143: ?? $this->phpParser = (new ParserFactory())->createForNewestSupportedVersion();
144: }
145:
146: public function originalPhpParser(): Parser
147: {
148: return $this->originalPhpParser
149: ?? $this->originalPhpParser = (new ParserFactory())->createForNewestSupportedVersion();
150: }
151:
152: public function astLocator(): AstLocator
153: {
154: return $this->astLocator
155: ?? $this->astLocator = new AstLocator($this->phpParser());
156: }
157:
158: public function findReflectionsOnLine(): FindReflectionOnLine
159: {
160: return $this->findReflectionOnLine
161: ?? $this->findReflectionOnLine = new FindReflectionOnLine($this->sourceLocator(), $this->astLocator());
162: }
163:
164: public function sourceStubber(): SourceStubber
165: {
166: return $this->sourceStubber
167: ?? $this->sourceStubber = new AggregateSourceStubber(
168: new PhpStormStubsSourceStubber($this->phpParser(), $this->printer(), self::$phpVersion),
169: new ReflectionSourceStubber($this->printer()),
170: );
171: }
172:
173: public function printer(): Standard
174: {
175: return $this->printer ?? $this->printer = new Standard(['shortArraySyntax' => true]);
176: }
177: }
178: