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