为啥在 Eloquent 模型中调用方法时出现“不应静态调用非静态方法”?

Posted

技术标签:

【中文标题】为啥在 Eloquent 模型中调用方法时出现“不应静态调用非静态方法”?【英文标题】:Why I'm getting 'Non-static method should not be called statically' when invoking a method in a Eloquent model?为什么在 Eloquent 模型中调用方法时出现“不应静态调用非静态方法”? 【发布时间】:2013-08-22 18:42:39 【问题描述】:

我试图在我的控制器中加载我的模型并尝试了这个:

return Post::getAll();

收到错误Non-static method Post::getAll() should not be called statically, assuming $this from incompatible context

模型中的函数如下所示:

public function getAll()


    return $posts = $this->all()->take(2)->get();


在控制器中加载模型然后返回其内容的正确方法是什么?

【问题讨论】:

2 种方式。 1、创建模型实例并使用$obj->getAll()或将函数设为静态。 当您使用::: 时,您正尝试静态地访问方法,因此您的函数签名应声明为:public static function getAll() @Sam,我会推荐你​​花五分钟阅读关于 php 中的 OOP 和静态方法:php.net/manual/en/language.oop5.static.php 【参考方案1】:

您将您的方法定义为非静态的,并尝试将其作为静态调用。那就是……

1.如果你想调用一个静态方法,你应该使用::并将你的方法定义为静态。

// Defining a static method in a Foo class.
public static function getAll()  /* code */ 

// Invoking that static method
Foo::getAll();

2.否则,如果你想调用一个实例方法,你应该实例化你的类,使用->

// Defining a non-static method in a Foo class.
public function getAll()  /* code */ 

// Invoking that non-static method.
$foo = new Foo();
$foo->getAll();

注意:在 Laravel 中,几乎所有 Eloquent 方法都返回模型的实例,允许您将方法链接起来,如下所示:

$foos = Foo::all()->take(10)->get();

在该代码中,我们静态地通过 Facade 调用 all 方法。之后,所有其他方法都被称为实例方法

【讨论】:

第二个选项中的 getAll() 如何是非静态的?? 感谢@TryingTobemyself 通知我。我根据您的建议更新了我的答案。 In Laravel, almost all Eloquent methods are defined as static.... 这是一个误解。 NONE 是静态的。 是的,在 Laravel 中,没有 Eloquent 方法被定义为静态的,我们可以使用它们,因为它被定义为静态,但这是一个门面,有关此的更多信息:laravel.com/docs/facades 尽管响应是真实的,但在 Laravel 的上下文中,这不太可能是该线程上的用户正在寻找的修复程序。应删除此答案,并将 keithics 答案标记为正确。【参考方案2】:

为什么不尝试添加范围? Scope 是 Eloquent 的一个非常好的特性。

class User extends Eloquent 

    public function scopePopular($query)
    
        return $query->where('votes', '>', 100);
    

    public function scopeWomen($query)
    
        return $query->whereGender('W');
    



$users = User::popular()->women()->orderBy('created_at')->get();

Eloquent #scopes in Laravel Docs

【讨论】:

IMO 这应该是公认的答案,因为它是 Laravel 特有的,而鲁本斯的答案是正确的,但不够具体。【参考方案3】:

TL;DR。您可以通过将查询表达为MyModel::query()->find(10); 而不是MyModel::find(10); 来解决此问题。

据我所知,对于 MyModel::where()MyModel::find() 等方法,启动 PhpStorm 2017.2 代码检查失败(检查此 thread)。这可能会很烦人,当您在提交代码之前尝试(比方说)使用 PhpStorm 的 Git 集成 时,PhpStorm 不会停止抱怨这些静态方法调用警告。

解决此问题的一种优雅方法 (IMOO) 是在任何有意义的地方显式调用 ::query()。这将使您受益于免费的自动完成和适合您查询的格式

示例

不好

检查抱怨静态方法调用的片段

$myModel = MyModel::find(10); // static call complaint

// another poorly formatted query with code inspection complaints
$myFilteredModels = MyModel::where('is_beautiful', true)
    ->where('is_smart', false)
    ->get();

格式良好的代码,没有任何抱怨

$myModel = MyModel::query()->find(10);

// a nicely formatted query with no complaints
$myFilteredModels = MyModel::query()
    ->where('is_beautiful', true)
    ->where('is_smart', false)
    ->get();

【讨论】:

更改代码只是为了删除 incorrect IDE 警告听起来是个坏主意。如果你知道它是正确的,那就保持这种状态。 @zundi 是的先生,我完全同意为了取悦 IDE 而更改代码并不总是一个好习惯,但是在这种情况下,我们只是添加一个静态方法调用,无论哪种方式都可以调用,(我们只是在这里明确)。否则,您将不得不:要么禁用此检查,要么在其他地方注释另一个类...(忙!你不同意吗?) 同样,我真的很喜欢这个答案。我一开始就不是 Facades 的忠实粉丝,而且 PhpStorm 不直接支持它们的事实让我不那么喜欢它们。 MyModel::query() 非常清楚底层发生了什么,同时也让 IDE 满意。【参考方案4】:

以防万一这有助于某人,我收到此错误是因为我完全错过了stated fact,即在调用本地范围时不得使用范围前缀。因此,如果您像这样在模型中定义本地范围:

public function scopeRecentFirst($query)

    return $query->orderBy('updated_at', 'desc');

你应该这样称呼它:

$CurrentUsers = \App\Models\Users::recentFirst()->get();

请注意,前缀scope 不存在于调用中。

【讨论】:

【参考方案5】:

原始问题的解决方案

您静态调用了非静态方法。要将模型中的公共函数设为静态,应如下所示:

public static function 
  

一般:

Post::get()

在这种特殊情况下:

Post::take(2)->get()

在定义关系和范围时,需要注意的一点是,当它们被命名相同时,我遇到了一个导致“不应静态调用非静态方法”错误的问题,例如:

public function category()
    return $this->belongsTo('App\Category');


public function scopeCategory()
    return $query->where('category', 1);

当我执行以下操作时,我得到了非静态错误:

Event::category()->get();

问题在于,Laravel 使用的是我的关系方法,称为类别,而不是我的类别范围 (scopeCategory)。这可以通过重命名范围或关系来解决。我选择重命名关系:

public function cat()
    return $this->belongsTo('App\Category', 'category_id');

请注意我定义了外键 (category_id),否则 Laravel 会寻找 cat_id,但它不会找到它,因为我在数据库中将它定义为 category_id。

【讨论】:

【参考方案6】:

你可以这样给予

public static function getAll()


    return $posts = $this->all()->take(2)->get();


当你在你的控制器函数中静态调用时..

【讨论】:

你不能在静态方法中使用 $this【参考方案7】:

在我的案例中,我刚刚得到了答案。 我正在创建一个实现了 create 方法的系统,所以我收到了这个实际错误,因为我访问的是被覆盖的版本,而不是来自 Eloquent 的版本。

希望有帮助吗?

【讨论】:

【参考方案8】:

检查您是否没有在模型中声明方法 getAll()。这会导致控制器认为您正在调用非静态方法。

【讨论】:

【参考方案9】:

要使用像return Post::getAll(); 这样的语法,你应该在你的类中有一个神奇的函数__callStatic 来处理所有的静态调用:

public static function __callStatic($method, $parameters)

    return (new static)->$method(...$parameters);

【讨论】:

以上是关于为啥在 Eloquent 模型中调用方法时出现“不应静态调用非静态方法”?的主要内容,如果未能解决你的问题,请参考以下文章

尝试从 eloquent 的查询中插入值时出现问题

为啥在我的 Web 服务中调用此方法时出现错误“无法将类型 'void' 隐式转换为 'string'?

为啥从 Word doc 调用宏时出现错误 1004,而不是从 Excel 调用?

为啥在 dbt 中运行模型时出现“关系 <y> 的列 <x> 不存在”错误,但在 SQL 客户端中运行时却没有?

为啥在 Laravel 中保存数据时出现方法不允许错误?

不确定为啥在使用 SQLAlchemy 时出现线程 ID 错误