Skip to content

Infer return type from class-string<T> in ClassResolver extensions#965

Merged
mglaman merged 1 commit intomainfrom
class-resolver-class-string-generics
Apr 8, 2026
Merged

Infer return type from class-string<T> in ClassResolver extensions#965
mglaman merged 1 commit intomainfrom
class-resolver-class-string-generics

Conversation

@mglaman
Copy link
Copy Markdown
Owner

@mglaman mglaman commented Apr 8, 2026

Summary

  • When class-string<T> is passed to ClassResolverInterface::getInstanceFromDefinition() or Drupal::classResolver(), PHPStan now infers the return type as T instead of object
  • Uses Type::getClassStringObjectType() to extract the generic class type in the no-constant-strings fallback path of DrupalClassResolverReturnType
  • Service-ID resolution (e.g. 'service_map.my_service'MyService) and constant class-name strings (Foo::class) are unchanged

This fills the gap that PR #402 was attempting to address, without replacing the dynamic extensions (which are still needed for service-ID resolution via ServiceMap).

Test plan

  • New test_class_string_vars() fixture function covers all four call patterns (ClassResolver, \Drupal::service('class_resolver'), \Drupal::classResolver()->..., \Drupal::classResolver($var)) with class-string<T> variables
  • php vendor/bin/phpunit --filter=DrupalContainerDynamicReturnTypeTest — all pass
  • php vendor/bin/phpcs src/ — clean

Closes #402

🤖 Generated with Claude Code

…nsions

When a variable typed as class-string<T> is passed to
ClassResolverInterface::getInstanceFromDefinition() or Drupal::classResolver(),
PHPStan now infers the return type as T instead of falling back to object.

The existing service-ID and constant-string class-name resolution via ServiceMap
is unchanged. This only fills the gap for non-constant class-string<T> variables.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mglaman mglaman force-pushed the class-resolver-class-string-generics branch from 75ef74a to 6a25edb Compare April 8, 2026 20:19
@mglaman mglaman requested a review from Copilot April 8, 2026 20:21
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improves PHPStan dynamic return type inference for Drupal’s class resolver so that passing a class-string<T> variable to ClassResolverInterface::getInstanceFromDefinition() / \Drupal::classResolver() yields return type T (rather than a generic object), while preserving existing behavior for service-id resolution and constant class-string literals.

Changes:

  • Extend DrupalClassResolverReturnType to extract and return the object type from class-string<T> inputs when the argument is not a constant string.
  • Add a new type inference fixture covering class-string<T> variables across the four supported call patterns.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/Type/DrupalClassResolverReturnType.php Uses Type::getClassStringObjectType() in the non-constant-string path to return the generic object type for class-string<T> arguments.
tests/src/Type/data/drupal-class-resolver.php Adds fixture assertions validating inferred return types for class-string<Foo> and class-string<MyService> variables across resolver call patterns.

@mglaman mglaman merged commit 676b6f5 into main Apr 8, 2026
18 of 19 checks passed
@mglaman mglaman deleted the class-resolver-class-string-generics branch April 8, 2026 20:36
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