我正在使用泛型来键入提示 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。
答案是:
/**
* @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 :)