为啥在 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 模型中调用方法时出现“不应静态调用非静态方法”?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在我的 Web 服务中调用此方法时出现错误“无法将类型 'void' 隐式转换为 'string'?
为啥从 Word doc 调用宏时出现错误 1004,而不是从 Excel 调用?