Tại sao tôi nhận được 'Phương thức không tĩnh không được gọi là phương thức tĩnh' khi gọi một phương thức trong mô hình Eloquent?


81

Tôi đang cố gắng tải mô hình của mình trong bộ điều khiển của mình và đã thử điều này:

return Post::getAll();

có lỗi Non-static method Post::getAll() should not be called statically, assuming $this from incompatible context

Hàm trong mô hình trông giống như sau:

public function getAll()
{

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

}

Cách chính xác để tải mô hình trong bộ điều khiển và sau đó trả về nội dung của nó là gì?


2 cách. Đầu tiên, tạo một phiên bản của mô hình và sử dụng $obj->getAll()hoặc làm cho hàm tĩnh.
itachi

5
Khi bạn sử dụng: ::bạn đang cố gắng truy cập vào một phương pháp tĩnh để chữ ký chức năng của bạn nên được khai báo là: public static function getAll().
Rubens Mariuzzo

@Sam, tôi sẽ khuyên bạn nên một lăm phút đọc về OOP & phương pháp tĩnh trong PHP: php.net/manual/en/language.oop5.static.php
Rubens Mariuzzo

Câu trả lời:


105

Bạn đã xác định phương thức của mình là không tĩnh và bạn đang cố gọi nó là tĩnh. Mà nói...

1. nếu bạn muốn gọi một phương thức tĩnh, bạn nên sử dụng ::và xác định phương thức của bạn là phương thức tĩnh.

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

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

2. ngược lại, nếu bạn muốn gọi một phương thức thể hiện, bạn nên thể hiện lớp của mình, hãy sử dụng ->.

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

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

Lưu ý : Trong Laravel, hầu hết tất cả các phương thức Eloquent đều trả về một thể hiện của mô hình của bạn, cho phép bạn xâu chuỗi các phương thức như được hiển thị bên dưới:

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

Trong mã mà chúng ta đang tĩnh gọi allphương pháp thông qua Facade. Sau đó, tất cả các phương thức khác đang được gọi là phương thức thể hiện .


getAll () non-static trong tùy chọn thứ 2 như thế nào ??
Đang dùng thử Tobemyself

1
Cảm ơn @TryingTobemyself đã thông báo cho tôi về điều này. Tôi đã cập nhật câu trả lời của mình với gợi ý của bạn.
Rubens Mariuzzo

9
In Laravel, almost all Eloquent methods are defined as static.... đó là một quan niệm sai lầm. KHÔNG CÓ tĩnh.
itachi

@itachi, làm ơn, bạn có thể giải thích quan niệm sai lầm?
Rubens Mariuzzo

4
Có, trong Laravel, không ai trong phương pháp hùng biện được định nghĩa là tĩnh , chúng ta có thể sử dụng chúng như nó đã được định nghĩa là tĩnh, nhưng đó là một mặt tiền, thêm về điều này: laravel.com/docs/facades
Rubens Mariuzzo

36

Tại sao không thử thêm Phạm vi? Phạm vi là một tính năng rất tốt của 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();

#Scope hùng hồn trong Laravel Docs


2
IMO đây phải là câu trả lời được chấp nhận vì nó dành riêng cho Laravel và câu trả lời của Rubens là đúng nhưng không đủ cụ thể.
JacobRossDev

7

TL; DR . Bạn có thể giải quyết vấn đề này bằng cách MyModel::query()->find(10);thay vì thể hiện các truy vấn của mình MyModel::find(10);.

Để theo sự hiểu biết của tôi, bắt đầu PhpStorm 2017,2 đang kiểm tra không cho các phương pháp như MyModel::where(), MyModel::find(), vv (kiểm tra này chủ đề ). Điều này có thể khá khó chịu, khi bạn cố gắng sử dụng tích hợp Git của PhpStorm trước khi cam kết mã của bạn, PhpStorm sẽ không ngừng phàn nàn về các cảnh báo cuộc gọi phương thức tĩnh này.

Một cách thanh lịch (IMOO) để giải quyết vấn đề này là gọi một cách rõ ràng::query() bất cứ nơi nào có ý nghĩa. Điều này sẽ cho phép bạn hưởng lợi từ tính năng tự động hoàn thành miễn phí và định dạng truy vấn đẹp.

Ví dụ

Đoạn mã trong đó kiểm tra phàn nàn về các cuộc gọi phương thức tĩnh

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

Mã định dạng tốt không có khiếu nại

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

Thay đổi mã chỉ để xóa cảnh báo IDE không chính xác nghe có vẻ là một ý tưởng tồi. Nếu bạn biết nó chính xác, thì hãy giữ nó như vậy.
zundi 19/07/18

@zundi vâng thưa ngài, tôi hoàn toàn đồng ý rằng việc thay đổi mã vì lợi ích của IDE không phải lúc nào cũng là một phương pháp hay, NHƯNG trong trường hợp này, chúng tôi chỉ thêm một lệnh gọi phương thức tĩnh có thể được gọi theo một trong hai cách, (chúng tôi 'đang chỉ rõ ràng ở đây). Nếu không, bạn sẽ phải: hoặc vô hiệu hóa kiểm tra này, hoặc chú thích một lớp ở một nơi khác ... (một hối hả làm u không đồng ý!?)
Anis

1
Giống nhau, tôi thực sự thích câu trả lời này. Tôi không phải là một fan hâm mộ lớn của Facades để bắt đầu và thực tế là PhpStorm không hỗ trợ chúng ngay lập tức khiến tôi ít thích chúng hơn. MyModel::query()làm cho nó rất rõ ràng những gì đang xảy ra trong khi cũng làm hài lòng IDE.
michasaurus

3

Chỉ trong trường hợp điều này giúp ích cho ai đó, tôi đã gặp lỗi này vì tôi đã hoàn toàn bỏ lỡ thực tế đã nêu rằng tiền tố phạm vi không được sử dụng khi gọi phạm vi cục bộ. Vì vậy, nếu bạn đã xác định phạm vi cục bộ trong mô hình của mình như thế này:

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

Bạn nên gọi nó như sau:

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

Lưu ý rằng tiền tố scopekhông có trong cuộc gọi.


0

Bạn có thể cho như thế này

public static function getAll()
{

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

}

Và khi bạn gọi tĩnh bên trong chức năng bộ điều khiển của bạn cũng ..


4
Bạn không thể bạn $ này bên trong một phương thức tĩnh
Luvias

0

Tôi thực sự vừa đi đến câu trả lời trong trường hợp của tôi. Tôi đang tạo một hệ thống đã triển khai phương thức tạo, vì vậy tôi gặp phải lỗi thực sự này vì tôi đang truy cập phiên bản bị ghi đè không phải từ Eloquent.

Mong rằng giúp đỡ?


0

Kiểm tra xem bạn có khai báo phương thức getAll () trong mô hình hay không. Điều đó khiến bộ điều khiển nghĩ rằng bạn đang gọi một phương thức không tĩnh.


0

Để sử dụng cú pháp như return Post::getAll();bạn nên có một hàm ma thuật __callStatictrong lớp của mình, nơi xử lý tất cả các lệnh gọi tĩnh:

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

0

Giải pháp cho câu hỏi ban đầu

Bạn đã gọi một phương thức không tĩnh là static. Để làm cho một hàm công khai tĩnh trong mô hình, sẽ giống như sau:

public static function {
  
}

Nói chung:

Post::get()

Trong trường hợp cụ thể này:

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

Một điều cần cẩn thận, khi xác định mối quan hệ và phạm vi, mà tôi đã gặp sự cố gây ra lỗi 'phương thức không tĩnh không được gọi là phương thức tĩnh' là khi chúng được đặt tên giống nhau, ví dụ:

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

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

Khi tôi làm như sau, tôi gặp lỗi không tĩnh:

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

Vấn đề là Laravel đang sử dụng phương thức quan hệ của tôi được gọi là danh mục, chứ không phải là phạm vi danh mục (scopeCategory) của tôi. Điều này có thể được giải quyết bằng cách đổi tên phạm vi hoặc mối quan hệ. Tôi đã chọn đổi tên mối quan hệ:

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

Vui lòng lưu ý rằng tôi đã xác định khóa ngoại (category_id) vì nếu không thì Laravel sẽ tìm cat_id thay thế và nó sẽ không tìm thấy nó, vì tôi đã định nghĩa nó là category_id trong cơ sở dữ liệu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.