PHP中如何为返回更具体类型的子类编写合规文档?
解决PHP抽象类子类方法更具体类型兼容问题
要让子类的getState/setState使用更具体的标量类型,同时通过Psalm/PHPStan的静态分析,核心是正确利用PHP的**模板泛型(@template)**机制,确保子类与基类的方法签名在参数化后保持兼容。
步骤1:正确定义带模板的抽象基类
基类需要用@template声明一个可替换的类型参数,让方法的参数/返回类型与该模板绑定:
<?php /** * @template TState */ abstract class HasState { /** * @var TState */ protected $state; /** * @return TState */ abstract public function getState(); /** * @param TState $state */ abstract public function setState($state); }
步骤2:子类绑定具体模板类型并实现方法
子类通过@extends指定具体的模板类型,然后重写方法时使用对应的具体类型,此时静态分析工具会识别出这是基类模板实例化后的合法签名:
示例1:状态为string类型的子类
<?php /** * @extends HasState<string> */ class StringState extends HasState { public function getState(): string { return $this->state; } public function setState(string $state): void { $this->state = $state; } }
示例2:状态为array类型的子类
<?php /** * @extends HasState<array> */ class ArrayState extends HasState { public function getState(): array { return $this->state; } public function setState(array $state): void { $this->state = $state; } }
关键注意事项
- 必须确保基类的
@template声明与方法的类型注解完全绑定:getState返回TState,setState接收TState参数。 - 子类的
@extends必须明确指定具体类型(如string/array),这相当于告诉静态分析工具:“该子类是基类使用TState=string实例化后的版本”。 - 子类重写方法时的具体类型必须与
@extends中指定的模板类型一致,否则仍会触发签名不兼容错误。
这种方式既满足了子类使用具体类型的需求,又符合静态分析工具的类型检查规则,不会出现方法签名不兼容的报错。
内容的提问来源于stack exchange,提问作者Colin
相关产品推荐
相关产品推荐

