Skip to content

Prevent autoloader invocation when checking for PHP core classes#617

Open
fain182 wants to merge 8 commits into
mainfrom
claude/awesome-cray-1VliZ
Open

Prevent autoloader invocation when checking for PHP core classes#617
fain182 wants to merge 8 commits into
mainfrom
claude/awesome-cray-1VliZ

Conversation

@fain182
Copy link
Copy Markdown
Collaborator

@fain182 fain182 commented May 27, 2026

Summary

Fixes a bug where checkIsPhpCoreClass() could trigger the Composer autoloader during file parsing, causing a spurious "parsing error" and exit code 1 on valid PHP files.

How we found it

Reported via Sylius/Sylius#19003, where upgrading phparkitect from ^0.8 to ^1.0 broke the architectural check with:

❌ found parsing errors in these files:
Class "Doctrine\ODM\MongoDB\DocumentRepository" not found in file: TaxonomyBundle/Resources/config/services/integrations/doctrine/mongodb-odm.php

The file is a perfectly valid Symfony DI config. The error was triggered because phparkitect's own process called class_exists('Doctrine\ODM\MongoDB\DocumentRepository', true) while analysing it, which invoked the autoloader. Since the mongodb PHP extension was not installed in that CI environment, loading the class file threw a PHP Error that propagated out of class_exists() and was caught by FileParser's \Throwable handler — turning a valid file into a parsing error.

Fix

Pass $autoload = false to all *_exists() calls in checkIsPhpCoreClass(). PHP built-in classes are always pre-loaded; if a symbol is not already present in the process it cannot be a PHP internal class, so triggering the autoloader is both unnecessary and harmful.

https://claude.ai/code/session_01A9BJtoBs8od2HvUya66nq2

claude added 3 commits May 27, 2026 08:03
class_exists($className, $autoload=true) (the default) causes the Composer
autoloader to load arbitrary class files encountered during file parsing.
When an optional package is installed but a required PHP extension is missing
(e.g. doctrine/mongodb-odm installed, mongodb ext absent), loading the class
file throws a PHP Error that propagates through class_exists() and is caught
by FileParser's \Throwable handler – converting a valid PHP file into a
spurious parsing error and failing the check with exit code 1.

Fix: pass $autoload=false to all *_exists() checks in checkIsPhpCoreClass.
PHP built-in classes are always pre-loaded; any symbol that is not already
present in the process cannot be a PHP internal class, so triggering the
autoloader is both unnecessary and harmful.

Regression test: test_adding_dependency_on_unloaded_optional_vendor_class_does_not_throw

Reported by Sylius/Sylius#19003 – phparkitect upgrade from 0.8 to 1.0 broke
the architectural check due to this side-effect.

https://claude.ai/code/session_01A9BJtoBs8od2HvUya66nq2
@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

❌ Patch coverage is 90.90909% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 98.29%. Comparing base (c93d60c) to head (f478274).

Files with missing lines Patch % Lines
src/Analyzer/ClassDescriptionBuilder.php 90.90% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #617      +/-   ##
============================================
- Coverage     98.33%   98.29%   -0.05%     
- Complexity      693      696       +3     
============================================
  Files            87       87              
  Lines          1981     1991      +10     
============================================
+ Hits           1948     1957       +9     
- Misses           33       34       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

claude added 5 commits May 27, 2026 14:51
enum_exists() is a PHP 8.1+ function. The symfony/polyfill-php81 bootstrap
is not in autoload_files so it is not loaded in the PHAR, meaning on PHP 8.0
the function does not exist at all.

In the previous code (autoload=true) this was harmless: class_exists() or
interface_exists() would short-circuit before enum_exists() was reached.
With autoload=false all three return false for unloaded symbols, so
enum_exists() is called for every dependency – throwing a Fatal Error on
PHP 8.0 that FileParser catches as a spurious parsing error.

Fix: skip the enum_exists() check on PHP < 8.1. Enums cannot exist on 8.0
so the guard is unnecessary there.

https://claude.ai/code/session_01A9BJtoBs8od2HvUya66nq2
Replace the chained negations with a dedicated method that reads
as a series of positive early-returns.

https://claude.ai/code/session_01A9BJtoBs8od2HvUya66nq2
- Countable (PHP built-in interface) must be detected and filtered
- UserTestTrait (user trait, pre-loaded by the test file) must pass
  through trait_exists() but NOT be filtered (isInternal() = false)

https://claude.ai/code/session_01A9BJtoBs8od2HvUya66nq2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants