Always skip Symfony polyfill packages in SkipPolyfillSourceLocator regardless of configured phpVersion#5633
Conversation
…regardless of configured phpVersion - `SkipPolyfillSourceLocator` previously only skipped polyfill packages when the configured phpVersion was >= the polyfill's target version (e.g., polyfill-php80 was only skipped when phpVersion >= 80000). This meant polyfill-provided functions like `str_ends_with` were treated as available when phpVersion was < 80000, even though they don't exist in the target PHP version. - Remove all phpVersion conditions from `SkipPolyfillSourceLocator` so polyfill packages are always skipped. Function/class availability is determined by PHPStan's version-aware PhpStorm stubs and function signature maps, not by polyfill source files. - Remove now-unused `PhpVersion` dependency from `SkipPolyfillSourceLocator` and `BetterReflectionSourceLocatorFactory`. - The fix covers all polyfill versions (php80-php85) and all symbol types (functions, classes, constants).
VincentLanglet
left a comment
There was a problem hiding this comment.
How do we know if the polyfill are loaded because of PHPStan or if they are installed/loaded voluntary by the user on his project ?
|
Tests pass and static analysis is clean. Now regarding the reviewer's question — there are no code changes needed here. The architecture already handles this correctly: The answer to VincentLanglet's question: It doesn't matter whether polyfills are installed because of PHPStan or voluntarily by the user. If a user voluntarily installs a polyfill and wants PHPStan to recognize those functions at a lower
These paths go through separate locator chains that are NOT wrapped by Since there are no code changes to make (the review is a design question answered by the existing architecture), there's nothing to commit or push. The appropriate response is to explain this rationale on the PR. |
Summary
When
phpVersionis configured to a lower PHP version (e.g., 70400 for PHP 7.4), functions introduced in later PHP versions likestr_ends_with()(PHP 8.0) were not reported as "Function not found" if a Symfony polyfill package providing that function was present in the project's dependencies.The
SkipPolyfillSourceLocatornow unconditionally skips all Symfony polyfill packages, so function/class/constant availability is determined solely by PHPStan's version-aware stubs and signature maps.Changes
SkipPolyfillSourceLocator::locateIdentifier()— polyfill packages are now always skipped regardless of configured phpVersion (src/Reflection/BetterReflection/SourceLocator/SkipPolyfillSourceLocator.php)PhpVersionconstructor parameter fromSkipPolyfillSourceLocatorBetterReflectionSourceLocatorFactoryto no longer passPhpVersiontoSkipPolyfillSourceLocator, and removed the now-unusedPhpVersiondependency (src/Reflection/BetterReflection/BetterReflectionSourceLocatorFactory.php)TestCaseSourceLocatorFactoryto match (src/Testing/TestCaseSourceLocatorFactory.php)SkipPolyfillSourceLocator— the fix applies to all of themRoot cause
SkipPolyfillSourceLocatorwas designed to skip polyfill source files only when the configured phpVersion was >= the polyfill's target (e.g., skipsymfony/polyfill-php80only when phpVersion >= 80000). The intent was to avoid conflicts when the native function already existed. However, this logic meant that when phpVersion was lower than the polyfill's target, the polyfill's function/class declarations were treated as legitimate symbols — the BetterReflection reflector found them through the composer source locator and returned them as valid functions, bypassing PHPStan's version-aware checks.The fix: always skip polyfill packages. PHPStan already has comprehensive, version-aware function/class databases (PhpStorm stubs with
@sinceannotations, function signature maps with version delta files). These are the authoritative sources for what exists in a given PHP version. Polyfill source files should never influence function availability determination.Test
CallToNonExistentFunctionRulePhp74Test::testBug11810— verifiesstr_ends_with,str_starts_with, andstr_containsare reported as "not found" when phpVersion is 70400 (PHP 7.4)CallToNonExistentFunctionRulePhp80Test::testBug11810— verifiesarray_is_listandenum_exists(PHP 8.1 functions) are reported as "not found" when phpVersion is 80000 (PHP 8.0)ValueError) are also correctly blocked for lower PHP versionsFixes phpstan/phpstan#11810