PhpStorm 检查中的“添加 #[Pure] 属性”检查是做什么的?

What is the "Add #[Pure] attribute" inspection in PhpStorm checking for?

提问人:miken32 提问时间:10/7/2021 最后编辑:LazyOnemiken32 更新时间:10/6/2022 访问量:15497

问:

我在 Laravel 项目中有一个非常简单的类。两个方法,它们都返回一个由方法部分填充的简单数组,但 IDE 以不同的方式处理它们。FormRequest

<?php

namespace App\Http\Requests;

class VerifyPhoneNumber extends FormRequest {
    use Support\ValidatesPhoneNumbers;

    public function authorize(): bool {
        return true;
    }

    public function rules(): array {
        return [
            "phone_number" => $this->getPhoneNumberRules(),
            "verify_code" => ["required", "numeric", "max:999999"],
        ];
    }

    public function messages(): array {
        return [
            "phone_number.regex" => $this->getPhoneNumberMessage(),
        ];
    }
}

以及最基本的特质方法:

<?php

namespace App\Http\Requests\Support;

trait ValidatesPhoneNumbers {
    protected function getPhoneNumberMessage(): string {
        return __("Some localized error message");
    }

    protected function getPhoneNumberRules(): array {
        return ["regex:/^\+?1?[2-9][0-9]{5,14}$/", "max:16"];
    }
}

令我感到困惑的是,IDE检查抱怨我应该将属性添加到方法中,而不是方法中。JetBrains\PhpStorm\Purerules()messages()

类定义中的注释说:

该属性标记对程序状态没有影响的函数或函数执行后使用的传递参数。 这意味着,如果之后未在代码中使用执行结果,则可以安全地删除解析为此类函数的函数调用。

这并没有真正给我任何线索,为什么它以不同的方式对待这两种方法。如果我正确理解了第二句话,当“纯”方法的结果未使用时,IDE 会将该方法的使用标记为未使用并建议将其删除。

用于确定何时需要此属性的逻辑是什么?

PHP 的 php风暴 php-8

评论


答:

6赞 Barmar 10/7/2021 #1

如果一个函数只依赖于其他纯函数,那么它也是纯函数。因为只返回一个固定的数组,所以它是纯的,所以也是纯的。getPhoneNumberRules()rules()

但是 calls ,它调用的函数可以在位置状态更改时返回不同的本地化消息,因此它不是纯的。messages()getPhoneNumberMessage()__()

评论

1赞 James 12/30/2021
感觉这个“纯粹”的东西对高维护敞开心扉。一旦方法更改,或者子方法或该方法使用的某些 DI'd 类发生更改,它可能不再是 Pure。
0赞 Barmar 12/30/2021
它本质上是一种文档形式(它只是以一种旨在供 IDE 使用的格式,而不是供人类直接使用)。因此,如果您更改函数的行为,则需要保持一致。
13赞 LazyOne 10/7/2021 #2

该方法具有固定(最好说“无副作用”)结果 - 它仅使用固定值。当然,它从特征调用,但它也返回固定数组(始终相同)。它不会在其他任何位置(内部状态或外部存储)进行更改。rules()getPhoneNumberRules()

该方法从特征中调用一个方法,该特征调用以获取已翻译的消息...它可能来自不同的源(数据库、文件),因此如果存储(文件/数据库)不可读,则可能会引发异常。IDE 不确定是否对文件/数据库进行了更改 -- 它没有注释为纯文件,并且 PhpStorm 无法从它使用的方法中做出这样的决定。messages()__()__()


附言如果此检查惹恼了您(我可以理解),那么我建议您忽略此类检查并将其在 PhpStorm 设置中的严重性降低为“不突出显示,仅修复”(Settings (Preferences on macOS) | Editor | Inspections | PHP | Attributes | '#[Pure]' attribute can be added)

评论

2赞 Noah Boegli 10/7/2021
不是 OP,但我在理解为什么更改本地化消息会使其不“纯粹”时遇到一些麻烦。这个调用也引起了我的兴趣,但由于它是一种只读机制,这难道不是根据 JetBrains 给出的定义使其纯粹吗?__()
1赞 LazyOne 10/7/2021
@NoahBoegli读取文件(甚至数据库)以获取翻译。如果存储(文件/数据库)不可读,则此类操作可能会引发异常。当然,只读取文件/数据库,不修改文件/数据库。但 IDE 对此一无所知。更改并将其声明为 Pure,IDE 将为上述示例中的两种方法提供相同的方法。__()__()__()
1赞 hakre 10/7/2021
I/O 或资源错误的好点,我也想知道一点。但是,我认为更多的是 Phpstorm 无法完全完成分析,因此建议 100% 确定它是纯净的,并且只是纯净的。Phpstorm 无法知道所有库。
1赞 LazyOne 10/7/2021
#Pure在 PhpStorm 中,与其他语言/文学中的“纯函数”含义并不完全匹配。这就是为什么您可以找到将其重命名为 youtrack.jetbrains.com/issue/WI-56211 的建议。#[NoSideEffect
1赞 LazyOne 5/22/2022
@Brad 它仅用于 PhpStorm 的静态代码分析:1) blog.jetbrains.com/phpstorm/2020/10/phpstorm-2020-3-eap-4/#pure 2) github.com/JetBrains/phpstorm-attributes#pure
1赞 Caleb 10/7/2021 #3

将此属性用于不产生任何副作用的函数。所有这些 PHP 内部函数都已经在 PhpStorm 中标记了。

#[Pure]
function compare(Foo $a, Foo $b): int
{
    return $a->a <=> $b->b;
}

来源: https://github.com/JetBrains/phpstorm-attributes#pure

由于这个函数只在它自己做一些事情,所以它可以被称为#[Pure]函数,所以你通过PhpStorm知道这一点。

0赞 William Randokun 10/6/2022 #4

暂时忘记副作用。

纯函数是保证在使用相同参数调用时始终给出相同结果的函数。

如果您的应用程序调用它,它将得到特定的结果。然后,其他一些代码可能会更改应用程序区域设置,下次以完全相同的方式调用时(即不带参数),它可能会返回不同的结果,因为 or 函数会检查某些全局状态(区域设置)以决定要返回哪个字符串。$verifyPhoneNumberRequest->rules()$verifyPhoneNumberRequest->rules()__()trans()

纯函数仅依赖于它们的直接输入参数,而不依赖于某些可能在其他地方被修改过也可能没有被修改的外部状态。

纯函数的另一个标准是它们不修改非局部状态。完全有可能将整个数据库放在 getUsername() 方法中(或者导致破坏性较小但对调试修改的痛苦)。但是,如果该方法被标记为纯方法并被批准为纯方法,则可以保证不会发生这种情况。