为什么在Eloquent模型中调用方法时出现“不应静态调用非静态方法”的问题?


81

我试图在控制器中加载模型并尝试以下操作:

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()或使函数静态。
itachi

5
使用时,::您尝试静态访问方法,因此您的函数签名应声明为:public static function getAll()
鲁本斯·马里努佐

@Sam,我建议您花五分钟阅读有关PHP中的OOP和静态方法的信息:php.net/manual/en/language.oop5.static.php
Rubens Mariuzzo 2013年

Answers:


105

您将方法定义为非静态方法,并且试图将其调用为静态方法。那就是...

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()如何是非静态的?
尝试做自己2012年

1
感谢@TryingTobemyself将此通知我。我根据您的建议更新了答案。
鲁本斯·马里努佐

9
In Laravel, almost all Eloquent methods are defined as static....这是一个误解。没有一个是静态的。
itachi

@itachi,请,你能解释一下这个误解吗?
Rubens Mariuzzo 2014年

4
是的,在Laravel中,没有一种雄辩的方法被定义为static,我们可以使用它们,因为它被定义为static,但这是一个Facade,更多有关此信息:laravel.com/docs/facades
Rubens Mariuzzo 2014年

36

为什么不尝试添加范围?范围是口才的一个很好的功能。

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();

Laravel文档中雄辩的#scope


2
国际海事组织,这应该是公认的答案,因为它是针对Laravel的,鲁本斯的答案是正确的,但不够具体。
JacobRossDev

7

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

据我所知,从PhpStorm 2017.2代码检查失败的方法,如MyModel::where()MyModel::find()等(检查此线程)。这可能会很烦人,当您尝试在提交代码之前尝试使用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_not_smart', false)
    ->get();

格式正确的代码,没有任何抱怨

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

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

仅仅为了消除不正确的IDE警告而更改代码听起来是个坏主意。如果您知道这是正确的,请保持这种方式。
zundi

@zundi是的,先生,我完全同意,为了取悦IDE而更改代码并不总是一种好习惯,但是在这种情况下,我们只是添加了一个静态方法调用,该方法将被称为在这里只是明确的)。否则,您将不得不:禁用此检查,或在其他地方注释其他课程……(喧嚣!您不同意吗?)
Anis

1
一样,我真的很喜欢这个答案。首先,我不是Facades的忠实拥护者,而且PhpStorm不立即提供支持的事实使我不太喜欢它们。MyModel::query()可以很清楚地说明发生了什么,同时还取悦了IDE。
michasaurus,

3

以防万一这对某人有所帮助,因为我完全错过了声明的事实,即在调用本地作用域时不得使用作用域前缀,所以出现了此错误。因此,如果您像这样在模型中定义了本地范围,则:

public function scopeRecentFirst($query)
{
    return $query->orderBy('updated_at', 'desc');
}

您应该这样称呼它:

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

请注意,scope呼叫中没有前缀。


0

你可以这样给

public static function getAll()
{

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

}

当您在控制器函数内部进行静态调用时。


4
您不能在静态方法中使用$ this
Luvias 18-4-23

0

就我的情况而言,我确实已经找到了答案。我正在创建一个实现了create方法的系统,所以我遇到了这个实际错误,因为我正在访问重写版本而不是Eloquent的版本。

希望有帮助吗?



0

为了使用类似的语法,return Post::getAll();您应该__callStatic在类中具有一个魔术函数,该函数可以处理所有静态调用:

public static function __callStatic($method, $parameters)
{
    return (new static)->$method(...$parameters);
}

0

解决原始问题

您静态调用了一个非静态方法。要使公共函数在模型中静态化,将如下所示:

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。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.