1212use function is_file ;
1313use function json_decode ;
1414use function phpversion ;
15+ use function realpath ;
1516
1617/**
1718 * Activates the phpstan_turbo extension's shadowing classes.
@@ -62,6 +63,27 @@ public static function getIncompatibleLoadedVersion(): ?string
6263 return $ version === false ? 'unknown ' : $ version ;
6364 }
6465
66+ /**
67+ * The phar the running code is compiled from. Code compiled out of a phar
68+ * carries the phar:// prefix of the path the phar was opened with, and
69+ * Composer's bootstrap.php opens it through __DIR__, a resolved path. A
70+ * path another program passes in, such as one with '..' in it, is
71+ * resolved the same way, so that it matches that prefix.
72+ */
73+ private static function resolvePharPath (?string $ pharPath ): string
74+ {
75+ if ($ pharPath === null ) {
76+ return Phar::running (false );
77+ }
78+
79+ $ resolvedPath = realpath ($ pharPath );
80+ if ($ resolvedPath === false ) {
81+ return '' ;
82+ }
83+
84+ return $ resolvedPath ;
85+ }
86+
6587 private static function isCompatible (): bool
6688 {
6789 return self ::isLoaded () && phpversion ('phpstan_turbo ' ) === self ::EXPECTED_EXTENSION_VERSION ;
@@ -90,8 +112,13 @@ public static function isTypeCombinatorCacheEnabled(): bool
90112 * implement userland interfaces and may extend userland classes, resolved
91113 * through it) and before anything could autoload one of the shadowed
92114 * classes — a twin already declared cannot be shadowed.
115+ *
116+ * Another program that loads PHPStan's phar, Rector for example, passes
117+ * the path to that phar: Phar::running() only knows the phar that runs.
118+ *
119+ * @api
93120 */
94- public static function activateIfCompatible (): void
121+ public static function activateIfCompatible (? string $ pharPath = null ): void
95122 {
96123 if (!self ::isCompatible ()) {
97124 return ;
@@ -136,7 +163,7 @@ public static function activateIfCompatible(): void
136163 // would otherwise race on. Fork mode requires the guard, and
137164 // ForkParallelChecker only allows fork with the extension active.
138165 if (class_exists ('Phar ' , false )) {
139- $ pharPath = Phar:: running ( false );
166+ $ pharPath = self :: resolvePharPath ( $ pharPath );
140167 if ($ pharPath !== '' ) {
141168 Runtime::enablePharForkGuard ($ pharPath );
142169 }
@@ -178,9 +205,13 @@ public static function isTrustingOwnTypes(): bool
178205 * compiled earlier keeps its checks. Independent of activateIfCompatible()
179206 * — only the version gate matters here.
180207 *
208+ * Another program that loads PHPStan's phar, Rector for example, passes
209+ * the path to that phar: Phar::running() only knows the phar that runs.
210+ *
211+ * @api
181212 * @param list<string> $argv
182213 */
183- public static function trustOwnTypesIfSuitable (array $ argv ): void
214+ public static function trustOwnTypesIfSuitable (array $ argv, ? string $ pharPath = null ): void
184215 {
185216 if (!self ::isCompatible ()) {
186217 return ;
@@ -191,7 +222,7 @@ public static function trustOwnTypesIfSuitable(array $argv): void
191222 if (!class_exists ('Phar ' , false )) {
192223 return ;
193224 }
194- $ pharPath = Phar:: running ( false );
225+ $ pharPath = self :: resolvePharPath ( $ pharPath );
195226 if ($ pharPath === '' ) {
196227 return ;
197228 }
0 commit comments