Skip to content

When combining templated class-string and Generics, the concrete class is missing. #4971

Open

Description

@zonuexe

Bug report

Classes instantiated from a class string do not have a generic type. The use case in this case is a typed collection class factory function.

Code snippet that reproduces the problem

https://phpstan.org/r/b8d7d149-be06-42bd-941d-67758ffbd708

/**
 * @template T
 * @template K of IFoo
 * @param T $v
 * @param class-string<K> $class
 * @return K<T>
 */
function make2($v, string $class)
{
    return new $class($v);
}


$obj2 = make2(1, Foo::class); // I want to type Foo<int>
\PHPStan\dumpType($obj2); // Kept generic type "int", but unexpected typed as "IFoo" interface

Expected output

Type as Foo<int> and no error will be printed.

Activity

  1. added this to the Generics milestone on May 7, 2021
  2. rohm1 commented on May 22, 2021

    @rohm1
  3. phpstan-bot commented on Sep 23, 2021

    @phpstan-bot
    Contributor

    @zonuexe After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

    @@ @@
    -50: Function make2() should return IFoo<T> but returns K of IFoo.
    -54: Dumped type: Foo
    -57: Dumped type: IFoo<int>
    +-1: Internal error: PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule::findMethod(): Argument #2 ($classReflection) must be of type PHPStan\Reflection\ClassReflection, null given, called in /var/task/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php on line 40
    +Run PHPStan with --debug option and post the stack trace to:
    +https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md
    Full report
    Line Error
    -1 Internal error: PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule::findMethod(): Argument #2 ($classReflection) must be of type PHPStan\Reflection\ClassReflection, null given, called in /var/task/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php on line 40Run PHPStan with --debug option and post the stack trace to:https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md
  4. phpstan-bot commented on Feb 7, 2022

    @phpstan-bot
    Contributor

    @zonuexe After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

    @@ @@
    -50: Function make2() should return IFoo<T> but returns K of IFoo.
     54: Dumped type: Foo
     57: Dumped type: IFoo<int>
    Full report
    Line Error
    54 Dumped type: Foo
    57 Dumped type: IFoo<int>
  5. biozshock commented on Mar 30, 2022

    @biozshock

    @zonuexe Just solved the same issue: https://phpstan.org/r/9f25afc8-fad9-4005-b2d1-7de847cf2181

    Line 31 should have a IFoo<T> to let phpstan know what type is inside the IFoo

  6. homersimpsons commented on Jun 30, 2026

    @homersimpsons
    Contributor

    I think I have a similar issue with the following snippet: https://phpstan.org/r/5c4a72d8-e23a-4e4c-acc7-9db4b8c9577a. In particular this method does not seem to be correctly handled by phpstan:

        /**
         * @param class-string<TLinq> $linqClass
         *
         * @return TLinq<TKey, TValue>
         *
         * @template TLinq of Linq
         */
        public function to(string $linqClass): self
        {
            return new $linqClass($this);
        }

    For the record the snippet should still report an error as we would create a BarIterator<int, Foo>. I have other methods to do the cast but adding them here would add a lot of noise.

    Thanks a lot to PHPStan maintainers though as this tool really improves code quality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions