如何在PHP中正确应用泛型解决PhpStan类型报错问题
解决PhpStan泛型类型推断问题
问题根源
你的抽象测试类AbstractClassTest的createObject()方法返回object类型,PhpStan无法推断出具体是ClassA还是ClassB,因此调用getId()或getName()时会触发未定义方法的报错。需要通过泛型将测试类与目标类的类型绑定,让PhpStan明确返回对象的具体类型。
具体修改步骤
- 修正抽象类的返回类型绑定:将
createObject()的返回值与泛型参数T绑定,通过PHPDoc标注明确返回类型。 - 子类绑定具体泛型类型:子类不再声明泛型参数,直接在
@extends注解中指定对应的目标类作为泛型参数,让PhpStan明确当前测试类对应的对象类型。 - 简化接口泛型(可选):如果接口不需要泛型逻辑,可以移除
@template,核心绑定逻辑放在抽象测试类即可。
修改后的完整代码
<?php // ---------------------------------------- CLASSES class ClassA { public function getId(): int { return 123; } } class ClassB { public function getName(): string { return 'abc'; } } // ---------------------------------------- TESTS interface InterfaceForTest { public function getClassName(): string; } /** * @template T * @implements InterfaceForTest */ abstract class AbstractClassTest implements InterfaceForTest { /** * @return T */ public function createObject(): object { $class = $this->getClassName(); $object = new $class(); return $object; } } /** * @extends AbstractClassTest<ClassA> */ class ClassATest extends AbstractClassTest { public function getClassName(): string { return ClassA::class; } public function testA(): void { $obj = $this->createObject(); assert($obj->getId() === 123); } } /** * @extends AbstractClassTest<ClassB> */ class ClassBTest extends AbstractClassTest { public function getClassName(): string { return ClassB::class; } public function testB(): void { $obj = $this->createObject(); assert($obj->getName() === 'abc'); } }
关键说明
- 抽象类的
@template T声明了类型参数,createObject()通过@return T将返回值与该参数绑定,为类型推断提供依据。 - 子类通过
@extends AbstractClassTest<ClassA>明确告知PhpStan,当前测试类的泛型参数T对应ClassA,这样createObject()返回的对象类型会被精准推断,PhpStan就能识别对应类的方法。 - 若需要更严格的类型约束,可给泛型
T添加限制,比如@template T of object,确保T只能是对象类型。
内容的提问来源于stack exchange,提问作者Tim K.
相关产品推荐
相关产品推荐

