如何解决Psalm中DocblockTypeContradiction告警与运行时参数校验冲突?
解决Psalm的DocblockTypeContradiction警告同时保留运行时参数校验
针对你遇到的问题,这里提供几种实用方案,既能保留面向非Psalm用户的运行时参数校验,又能消除Psalm的警告:
方案1:直接抑制特定警告
在触发警告的代码行上方添加Psalm的抑制注释,明确告诉它忽略这个矛盾提示:
class Example { public const C_1 = 'val1'; public const C_2 = 'val2'; public const C_3 = 'val3'; /** * @param self::C_1 | self::C_2 $c */ public function __construct(string $c) { /** @psalm-suppress DocblockTypeContradiction */ if (!in_array($c, [self::C_1, self::C_2], true)) { throw new InvalidArgumentException('Unsupported value'); } } }
这种方式最简单直接,完全保留原有逻辑,只是让Psalm跳过对这行的矛盾检查。
方案2:调整注释逻辑,让Psalm认可校验的必要性
把参数的文档注释类型改为string,同时添加@psalm-assert注释,让Psalm知道这段校验代码会确保$c符合预期类型:
class Example { public const C_1 = 'val1'; public const C_2 = 'val2'; public const C_3 = 'val3'; /** * @param string $c * @psalm-assert self::C_1 | self::C_2 $c */ public function __construct(string $c) { if (!in_array($c, [self::C_1, self::C_2], true)) { throw new InvalidArgumentException('Unsupported value'); } } }
这样Psalm会理解:传入的参数原本是宽泛的string类型,经过校验后会被限定为self::C_1 | self::C_2,因此这段校验代码是有意义的,不会再抛出警告。同时非Psalm用户依然能得到运行时的参数校验保障。
方案3:使用枚举(PHP 8.1+)
如果你的项目支持PHP 8.1及以上版本,推荐用枚举替代类常量,这样可以同时实现编译时类型约束和运行时校验:
enum ExampleEnum: string { case C_1 = 'val1'; case C_2 = 'val2'; case C_3 = 'val3'; } class Example { public function __construct(ExampleEnum $c) { // 若需排除C_3,可添加如下判断 if ($c === ExampleEnum::C_3) { throw new InvalidArgumentException('Unsupported value'); } } }
枚举类型会在编译阶段就限制传入的参数值,同时运行时也会自动校验,完全无需手动写in_array检查,Psalm也不会有任何警告,是最优雅的解决方案。
内容的提问来源于stack exchange,提问作者XYZ
相关产品推荐
相关产品推荐

