Skip to content

Fix phpstan/phpstan#14366: call-to-function is deprecated, depending on PHP_VERSION#5295

Closed
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-zjbcb0e
Closed

Fix phpstan/phpstan#14366: call-to-function is deprecated, depending on PHP_VERSION#5295
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-zjbcb0e

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

When a deprecated function call (like curl_close()) is guarded by a PHP_VERSION_ID comparison (e.g., if (PHP_VERSION_ID < 80000)), PHPStan should not report a deprecation error if the scope's narrowed PHP version falls below the version where the function was deprecated.

Changes

  • Created src/Rules/RestrictedUsage/DeprecatedSinceVersionHelper.php — extracts the since version from #[Deprecated(since: 'X.Y')] attributes and compares it against the scope's PHP version range
  • Modified src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php — converts JetBrains\PhpStorm\Deprecated attributes from phpstorm-stubs into PHPStan AttributeReflection objects with Deprecated name, preserving the since and message arguments
  • Applied version-aware deprecation filtering in all 9 RestrictedUsage rule files:
    • src/Rules/RestrictedUsage/RestrictedFunctionUsageRule.php
    • src/Rules/RestrictedUsage/RestrictedFunctionCallableUsageRule.php
    • src/Rules/RestrictedUsage/RestrictedMethodUsageRule.php
    • src/Rules/RestrictedUsage/RestrictedMethodCallableUsageRule.php
    • src/Rules/RestrictedUsage/RestrictedStaticMethodUsageRule.php
    • src/Rules/RestrictedUsage/RestrictedStaticMethodCallableUsageRule.php
    • src/Rules/RestrictedUsage/RestrictedPropertyUsageRule.php
    • src/Rules/RestrictedUsage/RestrictedStaticPropertyUsageRule.php
    • src/Rules/RestrictedUsage/RestrictedClassConstantUsageRule.php

Root cause

PHPStan narrows the PHP version type when it encounters PHP_VERSION_ID comparisons, but the deprecation reporting in the vendor phpstan-deprecation-rules extension doesn't check the scope's PHP version against the function's deprecated-since version. The fix adds this check at the rule level in phpstan-src, where both the scope (with narrowed PHP version) and the function reflection (with attributes) are available.

A secondary issue was that JetBrains\PhpStorm\Deprecated attributes from phpstorm-stubs were not being converted to PHPStan AttributeReflection objects (because the JetBrains\PhpStorm\Deprecated class isn't recognized by the AttributeReflectionFactory). The fix explicitly converts these to Deprecated AttributeReflection objects in NativeFunctionReflectionProvider.

Test

Added tests/PHPStan/Rules/RestrictedUsage/Bug14366Test.php with test data in tests/PHPStan/Rules/RestrictedUsage/data/bug-14366.php. The test configures PHP 8.5 (where curl_close() is deprecated) and verifies that:

  • curl_close() inside if (PHP_VERSION_ID < 80000) does NOT produce a deprecation error
  • curl_close() outside any version guard DOES produce a deprecation error

Fixes phpstan/phpstan#14366

…precation version

- Added DeprecatedSinceVersionHelper to extract the `since` version from #[Deprecated] attributes
  and compare it against the scope's narrowed PHP version
- In NativeFunctionReflectionProvider, convert JetBrains\PhpStorm\Deprecated stub attributes
  to Deprecated AttributeReflection so the version info is accessible
- Applied version-aware deprecation filtering in all RestrictedUsage rules:
  RestrictedFunctionUsageRule, RestrictedMethodUsageRule, RestrictedStaticMethodUsageRule,
  RestrictedPropertyUsageRule, RestrictedStaticPropertyUsageRule,
  RestrictedClassConstantUsageRule, and their callable variants
- New regression test in tests/PHPStan/Rules/RestrictedUsage/Bug14366Test.php
Comment on lines +95 to +100
if (
str_ends_with($restrictedUsage->identifier, '.deprecated')
&& DeprecatedSinceVersionHelper::isScopeVersionBeforeDeprecation($constantReflection->getAttributes(), $scope->getPhpVersion())
) {
continue;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deprecations is only one use-case of Restricted* classes. we should not mix this use-case into the this abstract base-classes

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was the initial make phpstan run which failed due to the dead method detection. The re-run after adding @api passed cleanly, and the commit has been pushed.

@ondrejmirtes
Copy link
Copy Markdown
Member

I don't think I'd ever like what the bot came up with for this, this needs a human 😊

@ondrejmirtes
Copy link
Copy Markdown
Member

Also it's not a priority.

… to deprecation-rules extensions

The Restricted*UsageRule classes are generic infrastructure for all restricted
usage extensions, not just deprecations. Move the version-aware deprecation
filtering into the phpstan-deprecation-rules extensions where it belongs.

Mark DeprecatedSinceVersionHelper::isScopeVersionBeforeDeprecation as @api
since it is consumed by the deprecation-rules extension package.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@staabm staabm closed this Mar 25, 2026
@staabm staabm deleted the create-pull-request/patch-zjbcb0e branch March 25, 2026 07:43
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.

3 participants