如何在 PHP / PHPStan 中返回通用接口?

问题描述 投票:0回答:1

我正在使用泛型来键入提示 php/phpstan 中的一些类和接口。我想要实现的是一个函数返回一个接口对象,但带有通用提示:

class Car
{
}

/**
 * @template S of object
 */
interface BuilderInterface
{
    /**
     * @return S
     */
    public function build(): object;
}

/**
 * @implements BuilderInterface<Car>
 */
class CarBuilder implements BuilderInterface
{
    public function build(): object
    {
        return new Car();
    }
    
    public function notAnInterfaceFunc(): void
    {
    }
}

/**
 * @template T of BuilderInterface
 * @param class-string<T> $builderClass
 * @return T
 */
function createBuilder(string $builderClass): BuilderInterface
{   
    return new $builderClass();
}

/**
 * @template T of BuilderInterface
 * @param class-string<T> $builderClass
 * @return BuilderInterface
 */
function createBuilder1(string $builderClass): BuilderInterface
{   
    return new $builderClass();
}

$builder = createBuilder(CarBuilder::class);
\PHPStan\dumpType($builder->build()); // proper return object is of type Car
$builder->notAnInterfaceFunc(); // the function is callable


$builder1 = createBuilder1(CarBuilder::class);
\PHPStan\dumpType($builder1->build()); // return object is 'object'
$builder1->notAnInterfaceFunc(); // is not callable

看一下两个

createBuilder()
函数。第二个就像我想要的那样,返回一个
CarBuilder::class
接口,但它没有正确设置
CarBuilder
类的泛型类型。

我想要什么:

  • $builder->build()
    返回类型为
    Car
  • 的对象
  • notAnInterfaceFunc()
    不可调用

我制作了一个 phpstan Pastebin,因此您可以使用以下代码:https://phpstan.org/r/3fa3c78c-fff1-4590-8778-51e7475c470a

php generics phpstan
1个回答
0
投票

答案是:

/**
 * @template TS of object
 * @template T of BuilderInterface<TS>
 * @param class-string<T> $builderClass
 * @return BuilderInterface<TS>
 */
function createBuilder(string $builderClass): BuilderInterface
{   
    return new $builderClass();
}

https://github.com/phpstan/phpstan/discussions/10886

感谢 Mad-briller :)

© www.soinside.com 2019 - 2024. All rights reserved.