¿Por qué obtengo 'El método no estático no debe llamarse estáticamente' cuando invoco un método en un modelo Eloquent?

81

Estoy tratando de cargar mi modelo en mi controlador y probé esto:

return Post::getAll();

tengo el error Non-static method Post::getAll() should not be called statically, assuming $this from incompatible context

La función en el modelo se ve así:

public function getAll()
{

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

}

¿Cuál es la forma correcta de cargar el modelo en un controlador y luego devolver su contenido?

Sam Pettersson
fuente
2 maneras. Primero, cree una instancia del modelo y use $obj->getAll()o haga que la función sea estática.
itachi
5
Cuando se utiliza: ::usted está tratando de acceder a un método estático para que su firma de la función debe ser declarado como: public static function getAll().
Rubens Mariuzzo
@Sam, te recomendaré una lectura de cinco minutos sobre POO y métodos estáticos en PHP: php.net/manual/en/language.oop5.static.php
Rubens Mariuzzo

Respuestas:

105

Definió su método como no estático y está intentando invocarlo como estático. Dicho eso ...

1.Si desea invocar un método estático, debe usar ::y definir su método como estático.

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

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

2. de lo contrario, si desea invocar un método de instancia, debe instanciar su clase, use ->.

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

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

Nota : En Laravel, casi todos los métodos Eloquent devuelven una instancia de su modelo, lo que le permite encadenar métodos como se muestra a continuación:

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

En ese código estamos llamando estáticamente al allmétodo a través de Facade. Después de eso, todos los demás métodos se llaman como métodos de instancia .

Rubens Mariuzzo
fuente
¿Cómo es getAll () no estático en la segunda opción?
Probarme a mí mismo
1
Gracias @ TryingTobemyself por notificarme sobre esto. Actualicé mi respuesta con tu sugerencia.
Rubens Mariuzzo
9
In Laravel, almost all Eloquent methods are defined as static.... eso es un error. NINGUNO son estáticos.
itachi
@itachi, por favor, ¿puedes explicar el error?
Rubens Mariuzzo
4
Sí, en Laravel, ninguno de los métodos Eloquent está definido como estático , podemos usarlos como se definieron como estáticos, pero eso es una Fachada, más sobre esto: laravel.com/docs/facades
Rubens Mariuzzo
36

¿Por qué no intentar agregar Scope? El alcance es una característica muy buena de 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();

#Scopios elocuentes en Laravel Docs

keithics
fuente
2
En mi opinión, esta debería ser la respuesta aceptada porque es específica de Laravel y la respuesta de Rubens es correcta pero no lo suficientemente específica.
JacobRossDev
7

TL; DR . Puede evitar esto expresando sus consultas como en MyModel::query()->find(10);lugar de MyModel::find(10);.

A lo mejor de mi conocimiento, a partir PhpStorm 2.017,2 inspección de código falla por métodos tales como MyModel::where(), MyModel::find(), etc (marque este hilo ). Esto podría resultar bastante molesto, cuando intente, digamos, usar la integración de Git de PhpStorm antes de enviar su código, PhpStorm no dejará de quejarse de estas advertencias de llamadas a métodos estáticos.

Una forma elegante (IMOO) de evitar esto es llamar explícitamente a::query() donde tenga sentido. Esto le permitirá beneficiarse de un autocompletado gratuito y un buen formato de consulta.

Ejemplos

Fragmento donde la inspección se queja de llamadas a métodos estáticos

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

Código bien formateado sin quejas

$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
fuente
Cambiar el código solo para eliminar una advertencia de IDE incorrecta parece una mala idea. Si sabe que es correcto, manténgalo así.
zundi
@zundi, sí señor, estoy totalmente de acuerdo en que cambiar el código para complacer al IDE no siempre es una buena práctica, PERO en este caso, solo estamos agregando una llamada a un método estático que se habría llamado de cualquier manera, (nosotros solo estoy siendo explícito aquí). De lo contrario, tendría que: deshabilitar esta inspección o anotar otra clase en otro lugar ... (¡un ajetreo! ¿No estás de acuerdo?)
Anis
1
Igual, me gusta mucho esta respuesta. Para empezar, no soy un gran admirador de las fachadas, y el hecho de que PhpStorm no las admita desde el primer momento hace que me gusten menos. MyModel::query()deja muy claro lo que está sucediendo bajo el capó y al mismo tiempo agrada al IDE.
michasaurus
3

En caso de que esto ayude a alguien, recibí este error porque me perdí por completo el hecho de que el prefijo de alcance no debe usarse al llamar a un alcance local. Entonces, si definió un alcance local en su modelo de esta manera:

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

Deberías llamarlo así:

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

Tenga en cuenta que el prefijo scopeno está presente en la llamada.

punto net
fuente
0

Puedes dar así

public static function getAll()
{

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

}

Y cuando llamas estáticamente dentro de la función de tu controlador también ...

Karthiga
fuente
4
No puedes $ esto dentro de un método estático
Luvias
0

Literalmente, acabo de llegar a la respuesta en mi caso. Estoy creando un sistema que ha implementado un método de creación, por lo que recibí este error real porque estaba accediendo a la versión anulada, no a la de Eloquent.

Espero que te ayude

idro2k
fuente
0

Compruebe si no ha declarado el método getAll () en el modelo. Eso hace que el controlador piense que está llamando a un método no estático.

Julio González Ríos
fuente
0

Para usar la sintaxis return Post::getAll();, debería tener una función mágica __callStaticen su clase donde manejar todas las llamadas estáticas:

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

Solución a la pregunta original

Llamaste estáticamente a un método no estático. Para hacer una función pública estática en el modelo, se vería así:

public static function {
  
}

En general:

Post::get()

En este caso particular:

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

Una cosa con la que tener cuidado, al definir las relaciones y el alcance, con el que tuve un problema que causó un error de 'método no estático no debería llamarse estáticamente' es cuando tienen el mismo nombre, por ejemplo:

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

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

Cuando hago lo siguiente, obtengo el error no estático:

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

El problema es que Laravel está usando mi método de relación llamado categoría, en lugar de mi alcance de categoría (scopeCategory). Esto se puede resolver cambiando el nombre del alcance o la relación. Elegí cambiar el nombre de la relación:

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

Tenga en cuenta que definí la clave externa (category_id) porque, de lo contrario, Laravel habría buscado cat_id en su lugar y no lo habría encontrado, ya que lo había definido como category_id en la base de datos.

Darren Murphy
fuente