From d2359a00d1186cd68a9ef48955c2386961fc9b53 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Thu, 27 Aug 2026 18:15:12 +0200 Subject: [PATCH] Include a bootstrap autoloader's located files for real before re-running it The file-read trap's pseudo-include succeeds with dummy data, so a bootstrap autoloader that memoizes a require's result - deptrac's bootstrap caches $loader = require .../vendor/autoload.php in a closure static - is left holding an int instead of the class loader and never retries the require. The run-for-real fallback then re-runs a permanently broken autoloader and the class stays unresolvable: on a project using deptrac's contract interfaces this surfaced as "Internal error: Interface DEPTRAC_INTERNAL\...\EventSubscriberInterface not found", aborting the analysis. When the located files declare nothing under the wanted name and the redeclare gate allows a real run, include those files for real first - that performs the include the poisoned autoloader can no longer do itself. An autoload-infrastructure file registers its nested class loader, and locating the class again consults it through the file-read trap, so the class is still found statically. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fMtimQECyyBNKTmFddr8L --- .github/workflows/e2e-tests.yml | 3 +++ e2e/bug-15102d/dep/E2eNestedClassLoader.php | 21 +++++++++++++++++++ e2e/bug-15102d/dep/SomeInterface.php | 10 +++++++++ e2e/bug-15102d/dep/autoload.php | 8 +++++++ e2e/bug-15102d/dep/bootstrap.php | 21 +++++++++++++++++++ e2e/bug-15102d/phpstan.dist.neon | 6 ++++++ e2e/bug-15102d/test.php | 15 +++++++++++++ .../AutoloadFunctionsSourceLocator.php | 21 +++++++++++++++++++ 8 files changed, 105 insertions(+) create mode 100644 e2e/bug-15102d/dep/E2eNestedClassLoader.php create mode 100644 e2e/bug-15102d/dep/SomeInterface.php create mode 100644 e2e/bug-15102d/dep/autoload.php create mode 100644 e2e/bug-15102d/dep/bootstrap.php create mode 100644 e2e/bug-15102d/phpstan.dist.neon create mode 100644 e2e/bug-15102d/test.php diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 84f234836b..4ea4016bae 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -151,6 +151,9 @@ jobs: cd e2e/bug-15102c composer install ../../bin/phpstan analyze + - script: | + cd e2e/bug-15102d + ../../bin/phpstan analyze - script: | cd e2e/bug-14724 composer install diff --git a/e2e/bug-15102d/dep/E2eNestedClassLoader.php b/e2e/bug-15102d/dep/E2eNestedClassLoader.php new file mode 100644 index 0000000000..b40badffb8 --- /dev/null +++ b/e2e/bug-15102d/dep/E2eNestedClassLoader.php @@ -0,0 +1,21 @@ +register(); + +return $loader; diff --git a/e2e/bug-15102d/dep/bootstrap.php b/e2e/bug-15102d/dep/bootstrap.php new file mode 100644 index 0000000000..3999b34096 --- /dev/null +++ b/e2e/bug-15102d/dep/bootstrap.php @@ -0,0 +1,21 @@ +loadClass($class); + } +}); diff --git a/e2e/bug-15102d/phpstan.dist.neon b/e2e/bug-15102d/phpstan.dist.neon new file mode 100644 index 0000000000..ceaba424f3 --- /dev/null +++ b/e2e/bug-15102d/phpstan.dist.neon @@ -0,0 +1,6 @@ +parameters: + level: 8 + bootstrapFiles: + - dep/bootstrap.php + paths: + - test.php diff --git a/e2e/bug-15102d/test.php b/e2e/bug-15102d/test.php new file mode 100644 index 0000000000..8143081e89 --- /dev/null +++ b/e2e/bug-15102d/test.php @@ -0,0 +1,15 @@ +locateWithoutAutoloading($reflector, $identifier); + if ($reflection !== null) { + return $reflection; + } + foreach ($autoloadFunctions as $autoloadFunction) { $autoloadFunction($className);