当返回类型推导不正确时,如何防止 PhpStorm 中的错误警告?

问题描述

考虑以下代码

<?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 不应报告任何错误警告!我应该如何避免 PHPStorm 中的这些警告?

PhpStorm (2020.3) complains that: Return value is expected to be '\Illuminate\Database\Eloquent\Builder','MyModel' returned

解决方法

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

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

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

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


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

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

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


供参考:

,

这是不遵循“最佳实践”的结果。 MyModel 的类层次结构不提供 where 的方法;换句话说,在类层次结构中不存在这样的方法。但! Model 的父类确实提供了 magic method__call(),当调用对象上下文中的不可访问的方法(在您的情况下,方法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');
        //                 ^^^^^^^^^^^^
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...