为什么在 Eloquent 模型中调用方法时,我得到“不应该静态调用非静态方法”?

我尝试在我的控制器中加载我的模型,并尝试这样做:

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


}

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

256883 次浏览

You defined your method as non-static and you are trying to invoke it as static. That said...

1.if you want to invoke a static method, you should use the :: and define your method as static.

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


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

2.otherwise, if you want to invoke an instance method you should instance your class, use ->.

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


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

Note: In Laravel, almost all Eloquent methods return an instance of your model, allowing you to chain methods as shown below:

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

In that code we are statically calling the all method via Facade. After that, all other methods are being called as instance methods.

Why not try adding Scope? Scope is a very good feature of 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

You can give like this

public static function getAll()
{


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


}

And when you call statically inside your controller function also..

I've literally just arrived at the answer in my case. I'm creating a system that has implemented a create method, so I was getting this actual error because I was accessing the overridden version not the one from Eloquent.

Hope that help?

Check if you do not have declared the method getAll() in the model. That causes the controller to think that you are calling a non-static method.

For use the syntax like return Post::getAll(); you should have a magic function __callStatic in your class where handle all static calls:

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

TL;DR. You can get around this by expressing your queries as MyModel::query()->find(10); instead of MyModel::find(10);.

To the best of my knowledge, starting PhpStorm 2017.2 code inspection fails for methods such as MyModel::where(), MyModel::find(), etc (check this thread). This could get quite annoying, when you try (let's say) to use PhpStorm's Git integration before committing your code, PhpStorm won't stop complaining about these static method call warnings.

One elegant way (IMOO) to get around this is to explicitly call ::query() wherever it makes sense to. This will let you benefit from free auto-completion and a nice formatting for your queries.

Examples

BAD

Snippet where inspection complains about static method calls

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


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

GOOD

Well formatted code with no complaints

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


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

Just in case this helps someone, I was getting this error because I completely missed the stated fact that the scope prefix must not be used when calling a local scope. So if you defined a local scope in your model like this:

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

You should call it like:

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

Note that the prefix scope is not present in the call.

Solution to the original question

You called a non-static method statically. To make a public function static in the model, would look like this:

public static function {
  

}

In General:

Post::get()

In this particular instance:

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

One thing to be careful of, when defining relationships and scope, that I had an issue with that caused a 'non-static method should not be called statically' error is when they are named the same, for example:

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


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

When I do the following, I get the non-static error:

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

The issue, is that Laravel is using my relationship method called category, rather than my category scope (scopeCategory). This can be resolved by renaming the scope or the relationship. I chose to rename the relationship:

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

Please observe that I defined the foreign key (category_id) because otherwise Laravel would have looked for cat_id instead, and it wouldn't have found it, as I had defined it as category_id in the database.