Чому я отримую "Нестатичний метод не слід викликати статично" при виклику методу в красномовній моделі?


84

Я намагаюся завантажити свою модель у свій контролер і спробував це:

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 способи. По-перше, створіть екземпляр моделі та використовуйте $obj->getAll()або зробіть функцію статичною.
itachi

5
При використанні: ::ви намагаєтеся отримати доступ до методу статичний тому ваша функція підпис має бути визнана як: public static function getAll().
Рубенс Маріуццо

@Sam, я рекомендую вам п'ять хвилин читати про ООП та статичні методи в PHP: php.net/manual/en/language.oop5.static.php
Рубенс Маріуццо

Відповіді:


110

Ви визначили свій метод як нестатичний і намагаєтесь викликати його як статичний. Тим не менше ...

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

У цьому коді ми статично викликаємо allметод через Facade. Після цього всі інші методи викликаються як методи екземпляра .


як getAll () нестатичний у другому варіанті ??
Спроба Tobemyself

1
Дякую @TryingTobemyself, щоб повідомити мене про це. Я оновив свою відповідь вашою пропозицією.
Рубенс Маріуццо

9
In Laravel, almost all Eloquent methods are defined as static.... це помилкова думка. НЕ є статичними.
itachi

@itachi, будь ласка, ти можеш пояснити помилкове уявлення?
Рубенс Маріуццо

4
Так, у Laravel жоден красномовний метод не визначається як статичний , ми можемо використовувати їх так, як його визначали як статичний, але це Фасад, докладніше про це: laravel.com/docs/facades
Рубенс Маріуццо

36

Чому б не спробувати додати Scope? Сфера застосування - дуже гарна риса красномовства.

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 Docs


2
ІМО це має бути прийнятою відповіддю, оскільки вона специфічна для відповіді Ларавеля та Рубенса є правильною, але недостатньо конкретною.
JacobRossDev

8

TL; DR . Ви можете обійти це, висловивши свої запити MyModel::query()->find(10);замість MyModel::find(10);.

Наскільки мені відомо, починаючи PhpStorm 2017,2 інспекції код не для таких методів, як MyModel::where(), MyModel::find()і т.д. (перевірити цю нитку ). Це може стати досить неприємним, коли ви намагаєтесь, скажімо, використовувати інтеграцію Git PhpStorm перед тим, як зафіксувати ваш код, 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 не завжди є гарною практикою, АЛЕ в цьому випадку ми просто додаємо один виклик статичного методу, який би називався в будь-який спосіб, (ми просто тут явно). В іншому випадку вам доведеться: або вимкнути цю перевірку, або анотувати інший клас де-небудь ще ... (суєта! Ви не згодні?)
Аніс ЛУНІС,

1
Те саме, мені дуже подобається ця відповідь. Я не великий шанувальник Фасадів, з чого я починаю, і той факт, що 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
Ви не можете це $ всередині статичного методу
Luvias

0

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

Сподіваюся, що це допоможе?


0

Перевірте, чи не оголошено в моделі метод getAll (). Це змушує контролер думати, що ви викликаєте нестатичний метод.


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 у базі даних.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.