如何让PHPStan识别类实现中存在但接口未定义的方法?
解决PHPStan中调用未在接口定义方法的泛型问题
我有两个接口(ClienInterface、ClientFactoryInterface)以及对应的实现类(ConcreteClient、ConcreteApiClientFactory)。ConcreteClient包含一个未在ClienInterface中定义的方法mySpecificFunction(),调用该方法时触发PHPStan错误:Call to an undefined method ClienInterface::mySpecificFunction().
尝试通过泛型关联工厂与客户端类型,但未成功,当前代码及报错如下:
示例代码
<?php declare(strict_types = 1); interface ClienInterface { } /** @template TClienInterface of ClienInterface */ interface ClientFactoryInterface { public function getClientByType(string $type): ClienInterface; } class ConcreteClient implements ClienInterface { public function mySpecificFunction(): void {} } /** @implements ClientFactoryInterface<ConcreteClient> */ class ConcreteApiClientFactory implements ClientFactoryInterface { public function getClientByType(string $type): ClienInterface { return new ConcreteClient(); } } class Test { public function __construct( private readonly ClientFactoryInterface $factory ) {} public function getClient(string $type): void { $client = $this->factory->getClientByType($type); $client->mySpecificFunction(); } }
错误信息
Method Test::__construct() has parameter $factory with generic interface ClientFactoryInterface but does not specify its types: TClienInterface
Call to an undefined method ClienInterface::mySpecificFunction().
解决方案
要解决这两个错误,需要正确配置泛型,让PHPStan能推断出工厂返回的具体客户端类型:
- 修正工厂接口的返回类型:将
ClientFactoryInterface的getClientByType返回值改为泛型参数TClienInterface,而非父接口ClienInterface,这样实现类可以返回具体的客户端类型。 - 更新实现类的返回类型:
ConcreteApiClientFactory的getClientByType方法返回值改为ConcreteClient,匹配泛型声明。 - 指定Test类中工厂的泛型类型:在
Test构造函数的参数中明确ClientFactoryInterface<ConcreteClient>,让PHPStan知道该工厂返回的是ConcreteClient实例。
修改后的代码
<?php declare(strict_types = 1); interface ClienInterface { } /** @template TClienInterface of ClienInterface */ interface ClientFactoryInterface { // 使用泛型参数作为返回类型 public function getClientByType(string $type): TClienInterface; } class ConcreteClient implements ClienInterface { public function mySpecificFunction(): void {} } /** @implements ClientFactoryInterface<ConcreteClient> */ class ConcreteApiClientFactory implements ClientFactoryInterface { // 返回具体的ConcreteClient类型 public function getClientByType(string $type): ConcreteClient { return new ConcreteClient(); } } class Test { // 明确工厂的泛型类型为ConcreteClient public function __construct( private readonly ClientFactoryInterface<ConcreteClient> $factory ) {} public function getClient(string $type): void { $client = $this->factory->getClientByType($type); $client->mySpecificFunction(); // PHPStan现在能识别该方法 } }
说明
- 泛型参数
TClienInterface在工厂接口中绑定了返回类型,确保实现类返回的客户端类型与泛型声明一致。 Test类中指定工厂的泛型类型后,PHPStan可以推断出getClientByType返回的是ConcreteClient,因此能识别mySpecificFunction()方法,不再报错。
内容的提问来源于stack exchange,提问作者piotr85
相关产品推荐
相关产品推荐

