From 86862c1bbd65a5debfc5595dc8f82c3fa5c2d349 Mon Sep 17 00:00:00 2001 From: staabm <120441+staabm@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:42:42 +0000 Subject: [PATCH 1/5] Consult bootstrap-registered custom autoloaders only after the static source locators - Move `AutoloadFunctionsSourceLocator` in `BetterReflectionSourceLocatorFactory` from the front of the locator chain to just before the runtime `AutoloadSourceLocator`, so it runs only as a fallback after the analysed-file, Composer class-map/PSR-4 and PHP-internal locators. - Previously the custom autoloaders registered by bootstrap files (stored in `__phpstanAutoloadFunctions`, from which Composer's own ClassLoader is deliberately excluded) were invoked eagerly for every class name, even for classes that Composer resolves statically at runtime. Because Composer's loader is registered first at runtime, those custom autoloaders are never reached for such classes - PHPStan invoking them anyway ran code paths that cannot happen at runtime (e.g. an autoloader that throws for a class Composer already provides). - Classes that only a custom autoloader can produce (e.g. `eval`'d classes) are still handled, since the locator remains in the chain as a last resort. - Adds e2e test `e2e/bug-12972b` reproducing the reported crash and wires it into the e2e workflow. --- .github/workflows/e2e-tests.yml | 4 ++++ e2e/bug-12972b/.gitignore | 2 ++ e2e/bug-12972b/autoloader.php | 9 ++++++++ e2e/bug-12972b/composer.json | 7 ++++++ e2e/bug-12972b/phpstan.dist.neon | 8 +++++++ e2e/bug-12972b/real-world.php | 6 +++++ e2e/bug-12972b/src/folder/file2.php | 9 ++++++++ e2e/bug-12972b/src/other/file.php | 10 +++++++++ .../BetterReflectionSourceLocatorFactory.php | 22 +++++++++++++------ 9 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 e2e/bug-12972b/.gitignore create mode 100644 e2e/bug-12972b/autoloader.php create mode 100644 e2e/bug-12972b/composer.json create mode 100644 e2e/bug-12972b/phpstan.dist.neon create mode 100644 e2e/bug-12972b/real-world.php create mode 100644 e2e/bug-12972b/src/folder/file2.php create mode 100644 e2e/bug-12972b/src/other/file.php diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 6a8715514db..cee3048c0d5 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -128,6 +128,10 @@ jobs: cd e2e/bug-14514 composer install ../../bin/phpstan analyze bug-14515.php + - script: | + cd e2e/bug-12972b + composer install + ../../bin/phpstan analyze - script: | cd e2e/bug-14724 composer install diff --git a/e2e/bug-12972b/.gitignore b/e2e/bug-12972b/.gitignore new file mode 100644 index 00000000000..3a9875b460f --- /dev/null +++ b/e2e/bug-12972b/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/bug-12972b/autoloader.php b/e2e/bug-12972b/autoloader.php new file mode 100644 index 00000000000..aaaae3ef08f --- /dev/null +++ b/e2e/bug-12972b/autoloader.php @@ -0,0 +1,9 @@ +doBar(new \other12972\MyClass()); diff --git a/e2e/bug-12972b/src/folder/file2.php b/e2e/bug-12972b/src/folder/file2.php new file mode 100644 index 00000000000..d81e18c01b5 --- /dev/null +++ b/e2e/bug-12972b/src/folder/file2.php @@ -0,0 +1,9 @@ +parser); - $locators[] = new AutoloadFunctionsSourceLocator( - new AutoloadSourceLocator($this->fileNodesFetcher, false), - new ReflectionClassSourceLocator( - $astLocator, - $this->reflectionSourceStubber, - ), - ); $analysedDirectories = []; $analysedFiles = []; @@ -184,6 +177,21 @@ public function create(): SourceLocator $this->phpVersion, )); + // Custom autoloaders registered by bootstrap files are consulted only + // as a fallback, after the static locators above (analysed files, + // Composer class map/PSR-4, PHP internals). At runtime Composer's + // class loader resolves such classes first, so their custom autoloaders + // are never invoked for them - invoking them eagerly here would run + // code paths that cannot happen at runtime. They remain useful for + // classes that only a custom autoloader can produce (e.g. eval'd). + $locators[] = new AutoloadFunctionsSourceLocator( + new AutoloadSourceLocator($this->fileNodesFetcher, false), + new ReflectionClassSourceLocator( + $astLocator, + $this->reflectionSourceStubber, + ), + ); + $locators[] = new AutoloadSourceLocator($this->fileNodesFetcher, true); $locators[] = new PhpVersionBlacklistSourceLocator(new PhpInternalSourceLocator($astLocator, $this->reflectionSourceStubber), $this->phpstormStubsSourceStubber); $locators[] = new PhpVersionBlacklistSourceLocator(new EvaledCodeSourceLocator($astLocator, $this->reflectionSourceStubber), $this->phpstormStubsSourceStubber); From 7ddee272861d092b5c181cb25979fe6d0d908a78 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 20 Jul 2026 16:55:48 +0200 Subject: [PATCH 2/5] move related lines in on block --- .../BetterReflection/BetterReflectionSourceLocatorFactory.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php index 1f5abf8c15e..afa7f21b0c7 100644 --- a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php +++ b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php @@ -97,8 +97,6 @@ public function create(): SourceLocator $locators[] = $this->optimizedSingleFileSourceLocatorRepository->getOrCreate($this->singleReflectionFile); } - $astLocator = new Locator($this->parser); - $analysedDirectories = []; $analysedFiles = []; @@ -184,6 +182,7 @@ public function create(): SourceLocator // are never invoked for them - invoking them eagerly here would run // code paths that cannot happen at runtime. They remain useful for // classes that only a custom autoloader can produce (e.g. eval'd). + $astLocator = new Locator($this->parser); $locators[] = new AutoloadFunctionsSourceLocator( new AutoloadSourceLocator($this->fileNodesFetcher, false), new ReflectionClassSourceLocator( From 90a36c42d9099a8e889bcf39e867e35da14193b8 Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Mon, 20 Jul 2026 15:33:05 +0000 Subject: [PATCH 3/5] Consult bootstrap autoloaders before/after Composer based on registration order Bootstrap-registered custom autoloaders were all consulted after the static source locators. That mirrors runtime only for autoloaders registered after Composer's class loader; one registered before it (e.g. spl_autoload_register($fn, true, true)) runs before Composer at runtime and must be consulted before the static Composer locators too. Detect each autoloader's position relative to Composer's ClassLoader in the spl_autoload queue and split them into a prepended and an appended group. The prepended group is consulted before the static locators (front of the chain), the appended group only as a fallback after them. Co-Authored-By: Claude Opus 4.8 --- bin/phpstan | 34 ++----- src/Command/CommandHelper.php | 23 +++-- .../BetterReflectionSourceLocatorFactory.php | 30 ++++-- .../AutoloadFunctionsSourceLocator.php | 11 ++- src/autoloadFunctions.php | 85 +++++++++++++++++ .../CollectNewAutoloadFunctionsTest.php | 92 +++++++++++++++++++ 6 files changed, 229 insertions(+), 46 deletions(-) create mode 100644 tests/PHPStan/CollectNewAutoloadFunctionsTest.php diff --git a/bin/phpstan b/bin/phpstan index 217a147ac1b..15e67dce78d 100755 --- a/bin/phpstan +++ b/bin/phpstan @@ -91,31 +91,15 @@ use Symfony\Component\Console\Helper\ProgressBar; $autoloadFunctionsAfter = spl_autoload_functions(); if ($autoloadFunctionsBefore !== false && $autoloadFunctionsAfter !== false) { - $newAutoloadFunctions = []; - foreach ($autoloadFunctionsAfter as $after) { - if ( - is_array($after) - && count($after) > 0 - ) { - if (is_object($after[0]) - && get_class($after[0]) === \Composer\Autoload\ClassLoader::class - ) { - continue; - } - if ($after[0] === 'PHPStan\\PharAutoloader') { - continue; - } - } - foreach ($autoloadFunctionsBefore as $before) { - if ($after === $before) { - continue 2; - } - } - - $newAutoloadFunctions[] = $after; - } - - $GLOBALS['__phpstanAutoloadFunctions'] = $newAutoloadFunctions; + $collectedAutoloadFunctions = \PHPStan\collectNewAutoloadFunctions($autoloadFunctionsBefore, $autoloadFunctionsAfter); + $GLOBALS['__phpstanAutoloadFunctions'] = array_merge( + $GLOBALS['__phpstanAutoloadFunctions'] ?? [], + $collectedAutoloadFunctions['appended'], + ); + $GLOBALS['__phpstanAutoloadFunctionsPrependedToComposer'] = array_merge( + $GLOBALS['__phpstanAutoloadFunctionsPrependedToComposer'] ?? [], + $collectedAutoloadFunctions['prepended'], + ); } $devOrPharLoader->register(true); diff --git a/src/Command/CommandHelper.php b/src/Command/CommandHelper.php index aa8a2a2210c..30cd4561dd2 100644 --- a/src/Command/CommandHelper.php +++ b/src/Command/CommandHelper.php @@ -41,6 +41,7 @@ use function array_filter; use function array_key_exists; use function array_map; +use function array_merge; use function array_values; use function class_exists; use function count; @@ -56,6 +57,7 @@ use function is_file; use function is_readable; use function is_string; +use function PHPStan\collectNewAutoloadFunctions; use function register_shutdown_function; use function spl_autoload_functions; use function sprintf; @@ -526,18 +528,15 @@ public static function begin( $autoloadFunctionsAfter = spl_autoload_functions(); if ($autoloadFunctionsBefore !== false && $autoloadFunctionsAfter !== false) { - $newAutoloadFunctions = $GLOBALS['__phpstanAutoloadFunctions'] ?? []; - foreach ($autoloadFunctionsAfter as $after) { - foreach ($autoloadFunctionsBefore as $before) { - if ($after === $before) { - continue 2; - } - } - - $newAutoloadFunctions[] = $after; - } - - $GLOBALS['__phpstanAutoloadFunctions'] = $newAutoloadFunctions; + $collectedAutoloadFunctions = collectNewAutoloadFunctions($autoloadFunctionsBefore, $autoloadFunctionsAfter); + $GLOBALS['__phpstanAutoloadFunctions'] = array_merge( + $GLOBALS['__phpstanAutoloadFunctions'] ?? [], + $collectedAutoloadFunctions['appended'], + ); + $GLOBALS['__phpstanAutoloadFunctionsPrependedToComposer'] = array_merge( + $GLOBALS['__phpstanAutoloadFunctionsPrependedToComposer'] ?? [], + $collectedAutoloadFunctions['prepended'], + ); } if (PHP_VERSION_ID >= 80000) { diff --git a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php index afa7f21b0c7..2a97a8e4efd 100644 --- a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php +++ b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php @@ -97,6 +97,21 @@ public function create(): SourceLocator $locators[] = $this->optimizedSingleFileSourceLocatorRepository->getOrCreate($this->singleReflectionFile); } + $astLocator = new Locator($this->parser); + + // Custom autoloaders that bootstrap files registered *before* Composer's + // class loader (e.g. spl_autoload_register($fn, true, true)) run before + // Composer resolves the class at runtime, so they are consulted before + // the static source locators below - mirroring that runtime order. + $locators[] = new AutoloadFunctionsSourceLocator( + new AutoloadSourceLocator($this->fileNodesFetcher, false), + new ReflectionClassSourceLocator( + $astLocator, + $this->reflectionSourceStubber, + ), + true, + ); + $analysedDirectories = []; $analysedFiles = []; @@ -175,14 +190,13 @@ public function create(): SourceLocator $this->phpVersion, )); - // Custom autoloaders registered by bootstrap files are consulted only - // as a fallback, after the static locators above (analysed files, - // Composer class map/PSR-4, PHP internals). At runtime Composer's - // class loader resolves such classes first, so their custom autoloaders - // are never invoked for them - invoking them eagerly here would run - // code paths that cannot happen at runtime. They remain useful for - // classes that only a custom autoloader can produce (e.g. eval'd). - $astLocator = new Locator($this->parser); + // Custom autoloaders registered *after* Composer's class loader are + // consulted only as a fallback, after the static locators above + // (analysed files, Composer class map/PSR-4, PHP internals). At runtime + // Composer's class loader resolves such classes first, so these custom + // autoloaders are never invoked for them - invoking them eagerly here + // would run code paths that cannot happen at runtime. They remain useful + // for classes that only a custom autoloader can produce (e.g. eval'd). $locators[] = new AutoloadFunctionsSourceLocator( new AutoloadSourceLocator($this->fileNodesFetcher, false), new ReflectionClassSourceLocator( diff --git a/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php index 3da44c64bf1..08807a281c7 100644 --- a/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php @@ -11,14 +11,21 @@ use function class_exists; use function interface_exists; use function PHPStan\autoloadFunctions; +use function PHPStan\autoloadFunctionsPrependedToComposer; use function trait_exists; final class AutoloadFunctionsSourceLocator implements SourceLocator { + /** + * @param bool $prependedToComposer When true, consult only the autoloaders + * registered before Composer's class loader (prepended); otherwise consult + * the ones registered after it (appended). + */ public function __construct( private AutoloadSourceLocator $autoloadSourceLocator, private ReflectionClassSourceLocator $reflectionClassSourceLocator, + private bool $prependedToComposer = false, ) { } @@ -35,7 +42,9 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): return null; } - $autoloadFunctions = autoloadFunctions(); + $autoloadFunctions = $this->prependedToComposer + ? autoloadFunctionsPrependedToComposer() + : autoloadFunctions(); foreach ($autoloadFunctions as $autoloadFunction) { $autoloadFunction($className); $reflection = $this->autoloadSourceLocator->locateIdentifier($reflector, $identifier); diff --git a/src/autoloadFunctions.php b/src/autoloadFunctions.php index 3239fe6aff6..617d7f7ee53 100644 --- a/src/autoloadFunctions.php +++ b/src/autoloadFunctions.php @@ -2,10 +2,95 @@ namespace PHPStan; +use Composer\Autoload\ClassLoader; +use function count; +use function get_class; +use function is_array; +use function is_object; + /** + * Autoloaders that were registered *after* Composer's class loader in the + * spl_autoload queue. At runtime Composer resolves the class first, so these + * are consulted only as a fallback, after the static source locators. + * * @return array */ function autoloadFunctions(): array // phpcs:ignore Squiz.Functions.GlobalFunction.Found { return $GLOBALS['__phpstanAutoloadFunctions'] ?? []; } + +/** + * Autoloaders that were registered *before* Composer's class loader in the + * spl_autoload queue (e.g. spl_autoload_register($fn, true, true)). At runtime + * these run before Composer resolves the class, so they must be consulted + * before the static Composer source locators to mirror that order. + * + * @return array + */ +function autoloadFunctionsPrependedToComposer(): array // phpcs:ignore Squiz.Functions.GlobalFunction.Found +{ + return $GLOBALS['__phpstanAutoloadFunctionsPrependedToComposer'] ?? []; +} + +/** + * Splits the autoload functions registered while loading Composer's autoloader + * and the bootstrap files into those registered before and after Composer's own + * class loader in the spl_autoload queue. This lets PHPStan consult them in the + * same order relative to Composer as PHP does at runtime, instead of always + * invoking them before (or after) the static Composer source locators. + * + * @param list|false $autoloadFunctionsBefore + * @param list|false $autoloadFunctionsAfter + * @return array{prepended: list, appended: list} + */ +function collectNewAutoloadFunctions($autoloadFunctionsBefore, $autoloadFunctionsAfter): array // phpcs:ignore Squiz.Functions.GlobalFunction.Found +{ + $prepended = []; + $appended = []; + + if ($autoloadFunctionsBefore === false || $autoloadFunctionsAfter === false) { + return ['prepended' => $prepended, 'appended' => $appended]; + } + + $composerIndex = null; + foreach ($autoloadFunctionsAfter as $index => $after) { + if ( + is_array($after) + && count($after) > 0 + && is_object($after[0]) + && get_class($after[0]) === ClassLoader::class + ) { + $composerIndex = $index; + break; + } + } + + foreach ($autoloadFunctionsAfter as $index => $after) { + if (is_array($after) && count($after) > 0) { + if ( + is_object($after[0]) + && get_class($after[0]) === ClassLoader::class + ) { + continue; + } + if ($after[0] === 'PHPStan\\PharAutoloader') { + continue; + } + } + + foreach ($autoloadFunctionsBefore as $before) { + if ($after === $before) { + continue 2; + } + } + + if ($composerIndex !== null && $index < $composerIndex) { + $prepended[] = $after; + } else { + $appended[] = $after; + } + } + + return ['prepended' => $prepended, 'appended' => $appended]; +} diff --git a/tests/PHPStan/CollectNewAutoloadFunctionsTest.php b/tests/PHPStan/CollectNewAutoloadFunctionsTest.php new file mode 100644 index 00000000000..9e2c18f551c --- /dev/null +++ b/tests/PHPStan/CollectNewAutoloadFunctionsTest.php @@ -0,0 +1,92 @@ +assertSame( + ['prepended' => [], 'appended' => []], + collectNewAutoloadFunctions(false, false), + ); + + $after = [static function (string $class): void { + }]; + $this->assertSame( + ['prepended' => [], 'appended' => []], + collectNewAutoloadFunctions(false, $after), + ); + } + + public function testAutoloadersAreSplitByComposerPosition(): void + { + $prepended = static function (string $class): void { + }; + $composer = new ClassLoader(); + $appended = static function (string $class): void { + }; + + $before = []; + $after = [$prepended, [$composer, 'loadClass'], $appended]; + + $result = collectNewAutoloadFunctions($before, $after); + + $this->assertSame([$prepended], $result['prepended']); + $this->assertSame([$appended], $result['appended']); + } + + public function testWithoutComposerEverythingIsAppended(): void + { + $first = static function (string $class): void { + }; + $second = static function (string $class): void { + }; + + $result = collectNewAutoloadFunctions([], [$first, $second]); + + $this->assertSame([], $result['prepended']); + $this->assertSame([$first, $second], $result['appended']); + } + + public function testComposerAndPharAutoloaderAndPreexistingAreExcluded(): void + { + $preexisting = static function (string $class): void { + }; + $composer = new ClassLoader(); + $bootstrap = static function (string $class): void { + }; + + $before = [$preexisting]; + $after = [$preexisting, [$composer, 'loadClass'], ['PHPStan\\PharAutoloader', 'loadClass'], $bootstrap]; + + $result = collectNewAutoloadFunctions($before, $after); + + $this->assertSame([], $result['prepended']); + $this->assertSame([$bootstrap], $result['appended']); + } + + public function testPreexistingAutoloaderBeforeComposerIsNotReported(): void + { + $preexisting = static function (string $class): void { + }; + $composer = new ClassLoader(); + $prependedBootstrap = static function (string $class): void { + }; + + // $preexisting was registered before PHPStan loaded the project - it must + // be ignored even though it sits before Composer in the queue. + $before = [$preexisting]; + $after = [$preexisting, $prependedBootstrap, [$composer, 'loadClass']]; + + $result = collectNewAutoloadFunctions($before, $after); + + $this->assertSame([$prependedBootstrap], $result['prepended']); + $this->assertSame([], $result['appended']); + } + +} From 93f01c285a9f17ca26946e25ab9b7a0d5360a0f4 Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Mon, 20 Jul 2026 15:33:10 +0000 Subject: [PATCH 4/5] Add e2e project for a prepended bootstrap autoloader bug-12972c registers a bootstrap autoloader before Composer's class loader that resolves a class Composer also maps, but with a different API. At runtime the prepended autoloader wins; PHPStan now reflects the same version instead of Composer's, so analysis matches runtime. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/e2e-tests.yml | 4 ++++ e2e/bug-12972c/.gitignore | 2 ++ e2e/bug-12972c/autoloader.php | 12 ++++++++++++ e2e/bug-12972c/classmap/Thing.php | 10 ++++++++++ e2e/bug-12972c/composer.json | 7 +++++++ e2e/bug-12972c/consumer/consumer.php | 10 ++++++++++ e2e/bug-12972c/phpstan.dist.neon | 8 ++++++++ e2e/bug-12972c/prepended/Thing.php | 10 ++++++++++ e2e/bug-12972c/real-world.php | 6 ++++++ 9 files changed, 69 insertions(+) create mode 100644 e2e/bug-12972c/.gitignore create mode 100644 e2e/bug-12972c/autoloader.php create mode 100644 e2e/bug-12972c/classmap/Thing.php create mode 100644 e2e/bug-12972c/composer.json create mode 100644 e2e/bug-12972c/consumer/consumer.php create mode 100644 e2e/bug-12972c/phpstan.dist.neon create mode 100644 e2e/bug-12972c/prepended/Thing.php create mode 100644 e2e/bug-12972c/real-world.php diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index cee3048c0d5..3d17425dd1a 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -132,6 +132,10 @@ jobs: cd e2e/bug-12972b composer install ../../bin/phpstan analyze + - script: | + cd e2e/bug-12972c + composer install + ../../bin/phpstan analyze - script: | cd e2e/bug-14724 composer install diff --git a/e2e/bug-12972c/.gitignore b/e2e/bug-12972c/.gitignore new file mode 100644 index 00000000000..3a9875b460f --- /dev/null +++ b/e2e/bug-12972c/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/bug-12972c/autoloader.php b/e2e/bug-12972c/autoloader.php new file mode 100644 index 00000000000..0eabb486506 --- /dev/null +++ b/e2e/bug-12972c/autoloader.php @@ -0,0 +1,12 @@ +prependedOnly(); +} diff --git a/e2e/bug-12972c/phpstan.dist.neon b/e2e/bug-12972c/phpstan.dist.neon new file mode 100644 index 00000000000..c9f081939c2 --- /dev/null +++ b/e2e/bug-12972c/phpstan.dist.neon @@ -0,0 +1,8 @@ +parameters: + level: 9 + + paths: + - consumer + + bootstrapFiles: + - autoloader.php diff --git a/e2e/bug-12972c/prepended/Thing.php b/e2e/bug-12972c/prepended/Thing.php new file mode 100644 index 00000000000..b97d6a4750d --- /dev/null +++ b/e2e/bug-12972c/prepended/Thing.php @@ -0,0 +1,10 @@ +prependedOnly(), "\n"; From 1a07961041bfcd870cd379c28cc0244a993b18d6 Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Mon, 20 Jul 2026 15:49:40 +0000 Subject: [PATCH 5/5] Require explicit $prependedToComposer argument on AutoloadFunctionsSourceLocator Callers now pass the boolean explicitly instead of relying on a default, making the prepended/appended intent visible at each construction site. Co-Authored-By: Claude Opus 4.8 --- .../BetterReflection/BetterReflectionSourceLocatorFactory.php | 1 + .../SourceLocator/AutoloadFunctionsSourceLocator.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php index 2a97a8e4efd..055df460810 100644 --- a/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php +++ b/src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php @@ -203,6 +203,7 @@ public function create(): SourceLocator $astLocator, $this->reflectionSourceStubber, ), + false, ); $locators[] = new AutoloadSourceLocator($this->fileNodesFetcher, true); diff --git a/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php index 08807a281c7..30ab9fa2d1f 100644 --- a/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/AutoloadFunctionsSourceLocator.php @@ -25,7 +25,7 @@ final class AutoloadFunctionsSourceLocator implements SourceLocator public function __construct( private AutoloadSourceLocator $autoloadSourceLocator, private ReflectionClassSourceLocator $reflectionClassSourceLocator, - private bool $prependedToComposer = false, + private bool $prependedToComposer, ) { }