【问题标题】:How to prevent a false-warning in PhpStorm when the return-type is deduced incorrectly?当返回类型被错误推断时,如何防止 PhpStorm 中的错误警告?
【发布时间】:2021-04-09 13:27:30
【问题描述】:

考虑以下代码:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
/**
 * Class MyModel
 * @package App\Models
 * @mixin Builder
 */
class MyModel extends Model
{
    public static function getGreens(): Builder
    {
        return (new self())->where('color', '=', 'green');
    }
}

return 声明中,PhpStorm (2020.3) 抱怨说:

返回值预计为'\Illuminate\Database\Eloquent\Builder',返回'MyModel'

并建议:

将返回类型从 '\Illuminate\Database\Eloquent\Builder' 更改为 'MyModel'

这是非常不正确的(where 方法确实返回了 \Illuminate\Database\Eloquent\Builder 的实例,而 IDE 将返回类型推断为 MyModel 类型)。通过删除返回类型,IDE 发出另一个警告:

缺少函数的返回类型声明

代码可以正常运行,但 IDE 不应报告任何 false 警告!我应该如何避免在 PhpStorm 中出现这些警告?

【问题讨论】:

  • 在我看来,应该使用local scope
  • 据我了解(据我记得 Laravel 的工作原理),这是因为 @mixin 行。 @mixin 的工作方式类似于 trait 的工作方式。因此,如果您有一个返回 $this / self 的特征中的方法,然后在类中使用该特征,则该方法的返回 ($this/self) 指向使用它的类。现在,AFAIR Builder::where() 也返回 $this / self .. 但它实际上不是一个 trait .. 但 Laravel 神奇地使 where() 方法在这个类中可用......
  • 问题来了:$this / self 实际上指向 Builder 类,但是当使用 作为特征(因为 @mixin)时,它被解析为IDE 当前的 MyModel 类。
  • 您可以使用@mixin 并忽略该问题(您可以通过Alt+Enter 快速修复菜单使用错误抑制——它会为IDE 添加一条注释,告诉您在此处忽略该特定问题) .. 或删除@mixin 并以不同方式声明这些方法。 AFAIK Laravel 帮助程序包应通过'@method PHPDoc 行将所有此类 Builder 方法添加到 Model 类(查看详细信息)。另一个建议——试试 Laravel Idea 插件——它是一个付费插件,但它使使用 Laravel 代码变得更加容易,而且 AFAIK 它应该涵盖这些基本内容。
  • @LazyOne 感谢您精心制作的 cmets,它们甚至也适合完整的答案!那么,您是否认为 PhpStorm 中 @mixin 的实现应该意识到这种情况并在该问题上暴露出细粒度的行为;还是需要解决源代码以避免问题?

标签: php laravel phpstorm


【解决方案1】:

这是未遵循“最佳做法”的结果。 MyModel 的类层次结构没有提供where 的方法;换句话说,这样的方法在类层次结构中不存在。但! Model 的父类确实提供了 __call()magic method,当调用对象上下文中的 无法访问的方法(在您的情况下为 where 的方法)时,它会被触发。它本质上是forwards the "call"\Illuminate\Database\Eloquent\Builder 的一个新实例,它具有所请求方法的实现(它是通过调用newQuery() 的方法获得的)。这种机制不仅对IDE不友好,而且slower

因此;删除@mixin 标签,而不是使用“魔术方法”,使用“本机访问”:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class MyModel extends Model
{
    public static function getGreens(): Builder
    {
        return (new self())->newQuery()->where('color', '=', 'green');
        //                 ^^^^^^^^^^^^
    }
}

【讨论】:

    【解决方案2】:

    据我了解(基于 ​​Laravel 的工作方式)这是因为 @mixin 行。

    @mixin 标签的工作方式类似于 PHP 的原生 trait 工作方式。因此,如果您有一个返回 $this / self 的特征中的方法,然后在类中使用该特征,则该方法的返回 ($this/self) 指向使用它的类。

    现在,Builder::where() 方法也返回 $thisself ... 但它实际上并不是一个 trait,但 Laravel 神奇地使 where() 方法在这个类中可用。

    问题来了:@return $this 实际上指向 Builder 类,但是当“作为特征”使用时(因为 @mixin)它被 IDE 解析为当前的 MyModel 类。


    您可以使用 @mixin 并忽略该问题(您可以通过 Alt + Enter 快速修复菜单使用错误抑制 - 它会为 IDE 添加注释以告知忽略该特定问题在此处发布).. 或删除 @mixin 并以不同方式声明这些方法。

    AFAIK Laravel helper package 应该通过 @method PHPDoc 行将所有此类 Builder 方法添加到 Model 类(查看详细信息,查看过去的问题以了解它如何以及为什么这样做等,例如 @987654323 @)。

    另一个建议:试试Laravel Idea plugin——它是一个付费插件,但它使使用 Laravel 代码更容易,而且 AFAIK 它应该涵盖这些基本内容。


    供参考:

    【讨论】:

      猜你喜欢
      • 2022-10-04
      • 1970-01-01
      • 2014-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-21
      • 2018-04-26
      • 1970-01-01
      相关资源
      最近更新 更多