Почему я получаю сообщение ‘Ненастатический метод не должен вызываться статически’ при вызове метода в модели Eloquent?

Вопросы и ответы

Я пытался загрузить мою модель в контроллере и попробовал это:

return Post::getAll();

И я все еще получаю ошибку

Нестатический метод Post::getAll() не должен вызываться статически, предполагая $this из несовместимого контекста

Функция в модели выглядит так:

public function getAll() {
   return $posts = $this->all()->take(2)->get();
}

Какой правильный способ загрузить модель в контроллер и затем вернуть ее содержимое?

Вы определили свой метод как нестатический и пытаетесь вызвать его статически. Это сказано…

1. Если вы хотите вызвать статический метод, вы должны использовать :: и определить свой метод как статический.

// Определение статического метода в классе Foo.
public static function getAll() { /* код */ }

// Вызов этого статического метода
Foo::getAll();

2. В противном случае, если вы хотите вызвать метод экземпляра, вы должны создать экземпляр вашего класса и использовать ->.

// Определение нестатического метода в классе Foo.
public function getAll() { /* код */ }

// Вызов этого нестатического метода.
$foo = new Foo();
$foo->getAll();

Примечание: В Laravel почти все методы Eloquent возвращают экземпляр вашей модели, что позволяет вам связывать методы, как показано ниже:

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

В этом коде мы статически вызываем метод all через Facade. После этого все другие методы вызываются как методы экземпляра.

Почему бы не попробовать добавить Scope? 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 в документации Laravel

Этот ответ касается построения запросов.

TL;DR. Вы можете обойти это, выразив свои запросы как MyModel::query()->find(10); вместо MyModel::find(10);.

Насколько я знаю, начиная с PhpStorm 2017.2, инспекция кода не работает для методов, таких как MyModel::where(), MyModel::find() и т. д. (проверьте этот тред), и это может быть очень неприятно.

Один (элегантный) способ обойти это — явно вызывать ::query() там, где это имеет смысл. Это даст вам бесплатное автозаполнение и красивую индентацию для ваших запросов.

Примеры

ПЛОХО

Фрагмент, где инспекция жалуется на вызовы статических методов

// жалоба на вызов статического метода
$myModel = MyModel::find(10); 

// еще один плохо отформатированный запрос с жалобами инспекции кода
$myFilteredModels = MyModel::where('is_foo', true)
    ->where('is_bar', false)
    ->get();

ХОРОШО

Хорошо отформатированный и отступленный код запроса БЕЗ жалоб

// нет жалоб
$myModel = MyModel::query()->find(10); 

// красиво отформатированный и отступленный запрос без жалоб
$myFilteredModels = MyModel::query()
    ->where('is_foo', true)
    ->where('is_bar', false)
    ->get();

На случай, если это поможет кому-то, я получал эту ошибку, потому что полностью пропустил указанный факт, что префикс scope не должен использоваться при вызове локального scope. Так что если вы определили локальный scope в своей модели вот так:

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

Вы должны вызывать его так:

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

Обратите внимание, что префикс scope не присутствует в вызове.

Решение оригинального вопроса

Вы вызвали нестатический метод статически. Чтобы сделать публичную функцию статической в модели, это будет выглядеть так:

public static function {

}

В общем:

Post::get()

В этом конкретном случае:

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

Нужно быть осторожным при определении отношений и scope, у меня была проблема, из-за которой возникла ошибка ‘нестатический метод не должен вызываться статически’, когда они назывались одинаково, например:

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

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

Когда я делаю следующее, у меня возникает ошибка нестатического метода:

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

Проблема в том, что Laravel использует мой метод отношения, который называется category, вместо моего scope category (scopeCategory). Это можно решить, переименовав scope или отношение. Я выбрал переименовать отношение:

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

Обратите внимание, что я определил внешний ключ (category_id), потому что иначе Laravel искал бы cat_id, и не нашел бы его, так как я определил его как category_id в базе данных.

Вы можете сделать так

public static function getAll()
{

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

}

И когда вы вызываете статически внутри функции вашего контроллера тоже..

Я буквально пришел к ответу в моем случае.
Я создаю систему, которая реализовала метод создания, поэтому я получал эту реальную ошибку, потому что я обращался к переопределенной версии, а не к той, что из Eloquent.

Надеюсь, это поможет?

Проверьте, не объявлен ли у вас метод getAll() в модели. Это заставляет контроллер думать, что вы вызываете нестатический метод.

Чтобы использовать синтаксис вроде return Post::getAll();, у вас должен быть магический метод __callStatic в вашем классе, который обрабатывает все статические вызовы:

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

public static function getAll() {
    return $posts = $this->all()->take(2)->get();
}

Просто добавьте статический метод.

Ответ

Ошибка "Non-static method should not be called statically" возникает, когда в вашем коде вы вызываете не статический метод класса как если бы он был статическим. В вашем случае вы определили метод getAll() как не статический:

public function getAll() {
   return $this->all()->take(2)->get();
}

Однако вы вызываете его статически в контроллере:

return Post::getAll();

Решение проблемы

Чтобы устранить эту ошибку, у вас есть два варианта:

  1. Измените метод на статический. Если вы хотите вызывать метод getAll() статически, то нужно добавить ключевое слово static к определению метода. Это будет выглядеть так:
public static function getAll() {
   return self::all()->take(2);
}

Затем вы сможете вызывать его как:

return Post::getAll();
  1. Создайте экземпляр модели и вызовите метод как не статический. Если вы не хотите изменять метод на статический, вы можете создать экземпляр модели и затем вызвать метод:
$post = new Post();
return $post->getAll();

Дополнительные советы

  • Если ваш метод getAll() должен работать с базой данных, то лучше использовать статические методы Eloquent, так как они предназначены для этого. Например:
public static function getAll() {
   return Post::take(2)->get();
}
  • Обратите внимание, что в Eloquent основным подходом является статическое использование методов для работы с моделями и их записями. Так что использование статических методов будет более идиоматичным для Laravel.

  • Если у вас есть локальные скоупы, помните, что вы должны вызывать их без префикса scope, чтобы избежать путаницы:
public function scopeRecent($query) {
    return $query->orderBy('created_at', 'desc');
}

// Использование скоупа
$posts = Post::recent()->get();

Заключение

В заключение, ошибка возникает из-за некорректного вызова метода. Для ее устранения измените метод на статический или создайте экземпляр модели перед вызовом метода. Надеюсь, это поможет вам решить вашу проблему!

Оцените материал
Добавить комментарий

Капча загружается...