Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Check constructor parameters in `NoPhpVersionInjectionInScopeAwareExt…
…ensionRule` via reflection and `ObjectType::isSuperTypeOf()`

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
  • Loading branch information
phpstan-bot and claude committed Sep 23, 2026
commit f69c8bae72e5e1cf0f200ce948d579538f4b0260
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
namespace PHPStan\Build;

use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InClassNode;
use PHPStan\Php\PhpVersion;
Expand All @@ -25,10 +23,12 @@
use PHPStan\Type\MethodParameterClosureTypeExtension;
use PHPStan\Type\MethodParameterOutTypeExtension;
use PHPStan\Type\MethodTypeSpecifyingExtension;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StaticMethodParameterClosureThisExtension;
use PHPStan\Type\StaticMethodParameterClosureTypeExtension;
use PHPStan\Type\StaticMethodParameterOutTypeExtension;
use PHPStan\Type\StaticMethodTypeSpecifyingExtension;
use PHPStan\Type\TypeCombinator;
use function sprintf;

/**
Expand Down Expand Up @@ -81,29 +81,25 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$constructor = $node->getOriginalNode()->getMethod('__construct');
if ($constructor === null) {
if (!$classReflection->hasConstructor()) {
return [];
}

$phpVersionType = new ObjectType(PhpVersion::class);
$errors = [];
foreach ($constructor->params as $param) {
$type = $param->type;
if ($type instanceof NullableType) {
$type = $type->type;
}
if (!$type instanceof Name || $type->toString() !== PhpVersion::class) {
foreach ($classReflection->getConstructor()->getOnlyVariant()->getParameters() as $parameter) {
if (!$phpVersionType->isSuperTypeOf(TypeCombinator::removeNull($parameter->getType()))->yes()) {
continue;
}

$errors[] = RuleErrorBuilder::message(sprintf(
'%s implements %s and should not inject %s. Use Scope::getPhpVersion() instead.',
'%s implements %s and should not inject %s via constructor parameter $%s. Use Scope::getPhpVersion() instead.',
$classReflection->getDisplayName(),
$implementedExtension,
PhpVersion::class,
$parameter->getName(),
))
->identifier('phpstan.phpVersionInjection')
->line($param->getStartLine())
->build();
}

Expand Down
2 changes: 1 addition & 1 deletion src/Type/Php/PDOConnectReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
* @see https://wiki.php.net/rfc/pdo_driver_specific_subclasses
* @see https://github.com/php/php-src/pull/12804
*/
// @phpstan-ignore phpstan.phpVersionInjection (PDO subclasses only exist in the runtime when running on PHP 8.4+)

Check failure on line 21 in src/Type/Php/PDOConnectReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, ubuntu-latest)

No error with identifier phpstan.phpVersionInjection is reported on line 21.

Check failure on line 21 in src/Type/Php/PDOConnectReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, windows-latest)

No error with identifier phpstan.phpVersionInjection is reported on line 21.
#[AutowiredService]
final class PDOConnectReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension

Check failure on line 23 in src/Type/Php/PDOConnectReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, ubuntu-latest)

PHPStan\Type\Php\PDOConnectReturnTypeExtension implements PHPStan\Type\DynamicStaticMethodReturnTypeExtension and should not inject PHPStan\Php\PhpVersion via constructor parameter $phpVersion. Use Scope::getPhpVersion() instead.

Check failure on line 23 in src/Type/Php/PDOConnectReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, windows-latest)

PHPStan\Type\Php\PDOConnectReturnTypeExtension implements PHPStan\Type\DynamicStaticMethodReturnTypeExtension and should not inject PHPStan\Php\PhpVersion via constructor parameter $phpVersion. Use Scope::getPhpVersion() instead.
{

public function __construct(
// @phpstan-ignore phpstan.phpVersionInjection (PDO subclasses only exist in the runtime when running on PHP 8.4+)
private PhpVersion $phpVersion,
)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public function testRule(): void
{
$this->analyse([__DIR__ . '/data/no-php-version-injection.php'], [
[
'NoPhpVersionInjection\InjectsPhpVersion implements PHPStan\Type\DynamicFunctionReturnTypeExtension and should not inject PHPStan\Php\PhpVersion. Use Scope::getPhpVersion() instead.',
24,
'NoPhpVersionInjection\InjectsPhpVersion implements PHPStan\Type\DynamicFunctionReturnTypeExtension and should not inject PHPStan\Php\PhpVersion via constructor parameter $phpVersion. Use Scope::getPhpVersion() instead.',
13,
],
]);
}
Expand Down
Loading