Eloquentモデルでメソッドを呼び出すときに、「非静的メソッドを静的に呼び出すべきではない」というメッセージが表示されるのはなぜですか?


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()、関数を使用または静的にします。
イタチ

5
を使用する場合:静的に::メソッドアクセスしようとしているため、関数のシグネチャは次のように宣言する必要がありますpublic static function getAll()
Rubens Mariuzzo 2013

@ Sam、PHPのOOPと静的メソッドについて5分間読むことをお勧めします:php.net/manual/en/language.oop5.static.php
Rubens Mariuzzo 2013

回答:


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

そのコードでは、Facadeを介してメソッドを静的に呼び出していallます。その後、他のすべてのメソッドがインスタンスメソッドとして呼び出されます


2番目のオプションでgetAll()はどのように非静的ですか?
しようとTobemyself

1
これについて私に通知してくれた@TryingTobemyselfに感謝します。私はあなたの提案で私の答えを更新しました。
Rubens Mariuzzo 2013

9
In Laravel, almost all Eloquent methods are defined as static....それは誤解です。NONEは静的です。
イタチ2013

@イタチ、お願いします、誤解を説明できますか?
Rubens Mariuzzo 2014年

4
はい、Laravelではありません。Eloquentメソッドは静的として定義されています。静的として定義されているので使用できますが、これはファサードです。詳細については、laravel.com
Rubens Mariuzzo 2014

36

スコープを追加してみませんか?スコープは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();

LaravelDocsのEloquent#scopes


2
IMOこれはLaravelに固有であり、Rubensの回答は正しいが十分に具体的ではないため、受け入れられる回答である必要があります。
JacobRossDev 2015年

8

TL; DR。のMyModel::query()->find(10);代わりにクエリを表現することで、これを回避できますMyModel::find(10);

私の知る限りでは、開始PhpStorm 2017.2コード検査は、次のような方法で失敗したMyModel::where()MyModel::find()など(このチェックスレッドを)。コードをコミットする前にPhpStormのGit統合を使用しようとすると、PhpStormはこれらの静的メソッド呼び出しの警告について文句を言うのをやめません。

これを回避するための1つのエレガントな方法(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を喜ばせるのためにコードを変更することは常に良い習慣ではないことに同意し、しかし我々は(この場合には、私たちはどちらかの方法を呼ばれただろうつの静的メソッドの呼び出しを追加していますここでは明示しているだけです)。それ以外の場合は、この検査を無効にするか、別のクラスに別の場所に注釈を付ける必要があります...(ハッスル!同意しませんか?)
AnisLOUNIS18年

1
同じように、私はこの答えが本当に好きです。私はそもそもファサードの大ファンではありません。PhpStormがすぐにファサードをサポートしていないという事実は、私がファサードを好きにならないようにします。MyModel::query()IDEを満足させながら、内部で何が起こっているのかを非常に明確にします。
ミカサウルス

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
静的メソッド内で$ thisを実行することはできません
Luvias 2018

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

関係とスコープを定義するときに注意すべきことの1つは、「非静的メソッドを静的に呼び出さないでください」というエラーが発生するという問題が発生したことです。たとえば、名前が同じである場合です。

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

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

次の手順を実行すると、非静的エラーが発生します。

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

問題は、Laravelがカテゴリスコープ(scopeCategory)ではなく、categoryと呼ばれるリレーションシップメソッドを使用していることです。これは、スコープまたは関係の名前を変更することで解決できます。関係の名前を変更することにしました。

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

外部キー(category_id)を定義したことに注意してください。そうしないと、Laravelは代わりにcat_idを検索し、データベースでcategory_idとして定義したため、それを見つけることができませんでした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.