Ваш вопрос содержит много деталей, которые не относятся к Laravel, но являются основами PHP. Наиболее существенным является различие между методами экземпляра, вызываемыми с помощью оператора стрелки ->
, и статическими методами, вызываемыми оператором двойной двойной точки ::
. Методы экземпляра используются, когда вызов метода относится к экземпляру класса (также называемого объектом), в то время как статические методы используются для вызовов методов, которые имеют отношение к классу, но не привязаны к экземпляру. Пример:
$dog = new Dog();
$dog->bark(); // only an actual dog can bark
echo Dog::species(); // "Canis lupus familiaris" will be the same species for all dogs
Имея эту информацию, мы можем теперь говорить о фактической разнице в методах Laravel.
Модель Query Builder
Для выполнения запросов SQL можно использовать построитель запросов моделей. Предоставляет удобный интерфейс для построения запросов. Большинство вызовов методов построителя запросов можно легко перевести на SQL. Следующие три утверждения одинаковы:
Dog::query(); // model query builder
DB::table('dogs'); // untyped query builder
FROM dogs // SQL
Для вас наиболее интересным является первый тип построителя запросов, поэтому вот более сложный пример:
Dog::query()
->where('color', 'brown')
->where('size', '>=', 50) // centimeter
->get();
// in SQL
SELECT *
FROM dogs
WHERE color = 'brown' AND size >= 50
Метод query()
является статическим методом базового класса Model
, который возвращает новый объект Illuminate\Database\Eloquent\Builder
. Некоторые люди предпочитают звонить query()
явно, но вы также можете пропустить вызов и использовать
Dog::where('color', 'brown')
->where('size', '>=', 50) // centimeter
->get();
вместо этого. Здесь базовый класс Model
будет использовать магическую функцию __callStatic()
для туннелирования вызова метода к where()
новому объекту Illuminate\Database\Eloquent\Builder
. Это просто для удобства, и вы правильно поняли - это буквально волшебство.
Отношения
Когда вы определяете отношение в модели, вы создаете функцию, которая возвращает что-то вроде HasMany
или BelongsTo
. Эти объекты создаются с помощью вспомогательных методов, вызываемых с помощью $this->hasMany()
или $this->belongsTo()
:
public function owner(): BelongsTo
{
$this->belongsTo(Person::class);
}
Когда вы сейчас вызываете это отношение (которое, как мы предполагаем, относится к классу Dog
), у вас есть два варианта:
$owner = $dog->owner()->first();
$owner = $dog->owner()->getResults(); // the same as first()
$owner = $dog->owner;
Первые две строки будут обращаться к взаимосвязи и выполнять фактический запрос SQL. Это в основном SELECT * FROM persons WHERE id = :owner_id:
. Вторая строка, с другой стороны, вернет свойство owner
объекта dog, которое может быть отношением. Если для объекта не установлено свойство owner
, и Laravel находит метод с именем owner()
(и метод возвращает отношение), Laravel загрузит это отношение с одной из первых двух строк, сохраняя его в owner
собственность и вернуть ее. Так что это снова волшебный аксессор для первого (+ он сохраняет результат). Более явная версия обоих вместе:
$dog->loadMissing('owner');
$owner = $dog->owner;
get()
и first()
Отношения, которые возвращают много результатов (например, HasMany
), потребуют от вас использовать get()
для получения результатов. Другие отношения, которые будут возвращать только один результат (например, BelongsTo
), потребуют от вас first()
. При непосредственном обращении к моделям (например, Dog::where('color', 'brown')->get()
), вы можете использовать оба, в зависимости от того, что вы хотите получить. first()
даст вам первую строку теоретического результата, которая требует от вас использовать orderBy()
в запросе (чтобы база данных знала, какая первая строка).
Как только вы получили список результатов с помощью get()
, у вас есть объект типа Illuminate\Database\Eloquent\Collection
, и вы больше не можете использовать методы построителя запросов. Здесь методы сбора применимы. Лучше всего, вы посмотрите на справочник метод .
Существует ловушка, так как вы можете использовать Dog::all()
, но не Dog::query()->all()
. Метод all()
является специальным и может быть переведен в Dog::query()->get()
.