php 如何解决诗篇中的DocblockTypeContradiction问题

to94eoyn  于 2023-11-16  发布在  PHP
关注(0)|答案(2)|浏览(91)

我从我的库中获得了简化的代码示例,由于我不理解的原因,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)
    {
       if (!in_array($c, [self::C_1, self::C_2], true)) {
            throw new InvalidArgumentException('Unsupported value');
        }
    }
}

字符串
if (!in_array($c, [self::C_1, self::C_2], true))行上显示警告,类型为DocblockTypeContradiction,消息为Docblock-defined type "val1" for $c is always string(val1)
据我所知,psalm需要删除检查if (!in_array($c, [self::C_1, self::C_2], true)),因为psalm已经检查了常量。但是如果一个使用我的库的用户在他的项目中不使用psalm怎么办?如何检查传递给构造函数的参数的正确性?
很抱歉我的英语不好。我希望我能解释这个问题。

anauzrmj

anauzrmj1#

问题是@param中的类型声明与方法签名中的声明不同。
检查in_array绝对是有意义的,因为正如你所说,不是每个人都将使用诗篇作为保证。
一种方法是只更改@param注解,让它知道您正在传递一个字符串,其中psalm is okay with

/**
 * @param string $c
 */

字符串
但这是多余的,因为PHP已经确保我们在那里有一个字符串,所以只需删除doc块works just as well

cwdobuhd

cwdobuhd2#

如果您希望Psalm帮助静态验证只有有效的参数被传入,但同时您仍然希望代码在用户没有使用Psalm进行预验证的情况下进行运行时验证,您最好的选择是保留所有内容,然后使用/** @psalm-suppress DocblockTypeContradiction */内联抑制问题。

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');
       }
    }
}

字符串
https://psalm.dev/r/2e8e443bbd
Psalm展示这个问题是有意义的,因为这是Psalm的重点,验证可以在静态分析时验证的东西,所以它们不必在运行时验证。但是你的用例也是有意义的,我认为抑制这个问题是最好的选择。
或者,你可以使用一个字符串支持的enum。如果你指定你的枚举作为构造函数参数的类型,你就不需要运行时验证或Psalm注解,因为php会在运行时为你验证它,实际的php类型提示将是足够的信息让Psalm去关闭。然后Psalm仍然可以静态地验证只有正确的类型被传递给任何想要使用Psalm的人。

相关问题