Dlaczego otrzymuję komunikat „Metoda niestatyczna nie powinna być wywoływana statycznie” podczas wywoływania metody w modelu elokwentnym?

84

Próbuję załadować mój model do mojego kontrolera i wypróbowałem to:

return Post::getAll();

otrzymałem błąd Non-static method Post::getAll() should not be called statically, assuming $this from incompatible context

Funkcja w modelu wygląda następująco:

public function getAll()
{

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

}

Jaki jest właściwy sposób załadowania modelu do kontrolera, a następnie zwrócenia jego zawartości?

Sam Pettersson
źródło
2 drogi. Najpierw utwórz instancję modelu i użyj $obj->getAll()lub ustaw funkcję statyczną.
itachi
5
Podczas korzystania z: ::próbujesz uzyskać dostęp do metody statycznie tak podpis funkcja powinna zostać uznana jako: public static function getAll().
Rubens Mariuzzo
@Sam, ja polecam ci pięć minut czytania o OOP i metody statyczne w PHP: php.net/manual/en/language.oop5.static.php
Rubens Mariuzzo

Odpowiedzi:

110

Zdefiniowałeś swoją metodę jako niestatyczną i próbujesz wywołać ją jako statyczną. To mówi...

1. jeśli chcesz wywołać metodę statyczną, powinieneś użyć ::i zdefiniować swoją metodę jako statyczną.

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

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

2. w przeciwnym razie, jeśli chcesz wywołać metodę instancji, powinieneś instancję swoją klasę, użyj ->.

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

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

Uwaga : w Laravel prawie wszystkie metody Eloquent zwracają instancję modelu, co pozwala łączyć metody w łańcuch, jak pokazano poniżej:

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

W tym kodzie statycznie wywołujemy allmetodę poprzez Facade. Następnie wszystkie inne metody są wywoływane jako metody instancji .

Rubens Mariuzzo
źródło
jak getAll () nie jest statyczne w drugiej opcji?
Trying Tobemyself
1
Dzięki @TryingTobemyself za powiadomienie mnie o tym. Zaktualizowałem odpowiedź o twoją sugestię.
Rubens Mariuzzo
9
In Laravel, almost all Eloquent methods are defined as static.... to błędne przekonanie. ŻADNE nie są statyczne.
itachi
@itachi, proszę, czy możesz wyjaśnić to nieporozumienie?
Rubens Mariuzzo
4
Tak, w Laravel żadna metoda Eloquent nie jest zdefiniowana jako statyczna , możemy ich używać tak, jak została zdefiniowana jako statyczna, ale to jest Fasada, więcej na ten temat: laravel.com/docs/facades
Rubens Mariuzzo,
36

Dlaczego nie spróbować dodać zakresu? Zakres jest bardzo dobrą cechą 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();

Elokwentne #scopes w Laravel Docs

keithics
źródło
2
IMO powinna to być akceptowana odpowiedź, ponieważ jest specyficzna dla Laravel i Rubens. Odpowiedź jest poprawna, ale nie wystarczająco konkretna.
JacobRossDev
8

TL; DR . Możesz obejść ten problem, wyrażając swoje zapytania jako MyModel::query()->find(10);zamiastMyModel::find(10); .

Do mojej najlepszej wiedzy, począwszy PhpStorm 2017,2 inspekcja kodu nie powiedzie się metodami, takimi jak MyModel::where(), MyModel::find()itp (sprawdź ten wątek ). Może to być dość denerwujące, gdy spróbujesz, powiedzmy, użyć integracji PhpStorm z Git przed zatwierdzeniem kodu, PhpStorm nie przestanie narzekać na te statyczne ostrzeżenia wywołań metod.

Jednym eleganckim sposobem (IMOO) na obejście tego jest jawne wywołanie::query() wszędzie tam, gdzie ma to sens. Pozwoli to skorzystać z bezpłatnego automatycznego uzupełniania i ładnego formatowania zapytań.

Przykłady

Fragment, w którym inspekcja skarży się na wywołania metod statycznych

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

Dobrze sformatowany kod bez reklamacji

$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();
Anis LOUNIS
źródło
Zmiana kodu tylko w celu usunięcia niepoprawnego ostrzeżenia IDE brzmi jak zły pomysł. Jeśli wiesz, że to prawda, zachowaj to w ten sposób.
zundi
@zundi tak, proszę pana, całkowicie się zgadzam, że zmiana kodu w celu zadowolenia środowiska IDE nie zawsze jest dobrą praktyką, ALE w tym przypadku dodajemy tylko jedno statyczne wywołanie metody, które można by nazwać tak czy inaczej (my są tu tylko wyraźne). W przeciwnym razie musiałbyś: albo wyłączyć tę inspekcję, albo dodać adnotację do innej klasy w innym miejscu ... (pośpiech! Nie zgadzasz się?)
Anis LOUNIS
1
To samo, naprawdę podoba mi się ta odpowiedź. Nie jestem wielkim fanem Fasady, a fakt, że PhpStorm nie obsługuje ich od razu po wyjęciu z pudełka, sprawia, że ​​mniej je lubię. MyModel::query()bardzo jasno pokazuje, co dzieje się pod maską, jednocześnie zadowalając IDE.
michasaurus
3

Na wszelki wypadek, gdyby to komuś pomogło, otrzymywałem ten błąd, ponieważ całkowicie przeoczyłem stwierdzony fakt, że prefiks zakresu nie może być używany podczas wywoływania zakresu lokalnego. Więc jeśli zdefiniowałeś lokalny zakres w swoim modelu w następujący sposób:

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

Powinieneś to nazwać tak:

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

Zauważ, że przedrostek scopenie jest obecny w wywołaniu.

dotNET
źródło
0

Możesz tak dawać

public static function getAll()
{

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

}

A kiedy dzwonisz statycznie wewnątrz funkcji kontrolera, również ...

Karthiga
źródło
4
Nie możesz tego zrobić w ramach statycznej metody
Luvias,
0

Dosłownie właśnie dotarłem do odpowiedzi w moim przypadku. Tworzę system, w którym zaimplementowano metodę tworzenia, więc otrzymywałem ten rzeczywisty błąd, ponieważ uzyskiwałem dostęp do wersji zastąpionej, a nie z Eloquent.

Mam nadzieję, że to pomoże?

idro2k
źródło
0

Sprawdź, czy nie zadeklarowałeś metody getAll () w modelu. To powoduje, że kontroler myśli, że wywołujesz metodę niestatyczną.

Julio Gonzalez Rios
źródło
0

Aby użyć składni, tak jak return Post::getAll();powinieneś mieć __callStaticw swojej klasie magiczną funkcję, która obsługuje wszystkie statyczne wywołania:

public static function __callStatic($method, $parameters)
{
    return (new static)->$method(...$parameters);
}
SpinyMan
źródło
0

Rozwiązanie pierwotnego pytania

Wywołałeś statyczną metodę statyczną. Aby uczynić funkcję publiczną statyczną w modelu, wyglądałoby to następująco:

public static function {
  
}

Ogólnie:

Post::get()

W tym konkretnym przypadku:

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

Jedną rzeczą, na którą należy uważać podczas definiowania relacji i zakresu, z którymi miałem problem, który spowodował błąd `` metody niestatycznej nie powinna być wywoływana statycznie '', jest sytuacja, gdy mają taką samą nazwę, na przykład:

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

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

Kiedy wykonuję następujące czynności, pojawia się błąd niestatyczny:

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

Problem polega na tym, że Laravel używa mojej metody relacji o nazwie category, a nie mojego zakresu kategorii (scopeCategory). Można to rozwiązać, zmieniając nazwę zakresu lub relacji. Zdecydowałem się zmienić nazwę relacji:

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

Zauważ, że zdefiniowałem klucz obcy (category_id), ponieważ w przeciwnym razie Laravel szukałby zamiast tego cat_id i nie znalazłby go, ponieważ zdefiniowałem go jako category_id w bazie danych.

Darren Murphy
źródło