Часть этой магии находится за паттерном фасада https://www.tutorialspoint.com/design_pattern/facade_pattern.htm
Но в случае с Laravel они используют статические методы в своих фасадах (\Illuminate\Support\Facades
пространство имен) и автоматически создают экземпляр для вызова этих методов из экземпляра.так что вам не нужно создавать экземпляр класса самостоятельно, чтобы начать использовать методы.Например, когда вы используете DB::
, Cache::
, Str::
для вызова статического метода.
Однако для Eloquent Laravel использует этот подход более внутренне, не подвергая модель пространству имен \Illuminate\Support\Facades
, настраивая EloquentМодель автоматически создает экземпляр Модели и создает \Illuminate\Database\Eloquent\Builder
Eloquent Builder и перенаправляет вызов этих статических методов в экземпляр Eloquent Builder или в экземпляр Query Builder.
Модель расширяет \Illuminate\Database\Eloquent\Model
, в которой есть специальный способ вызова любогометод статически во время выполнения.
/**
* Handle dynamic static method calls into the method.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters);
}
Таким образом, в определенный момент класс Builder Eloquent использует черту
use Illuminate\Support\Traits\ForwardsCalls;
для переадресации вызова друг другу, чтобы модель могла переслать своюстатический метод к методу из созданного экземпляра Eloquent Builder.Поэтому, если модель не имеет where
метода, она перенаправит его в метод where вновь созданного nstance Eloquent Builder.
Из взгляда на Facade Pattern, вот как Laravel вызывает метод изэкземпляр, но статическим образом:
// \Illuminate\Support\Facades\Facade.php
/**
* Handle dynamic, static calls to the object.
*
* @param string $method
* @param array $args
* @return mixed
*
* @throws \RuntimeException
*/
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
Таким образом, вызов User::where()
создает экземпляр \Illuminate\Database\Eloquent\Builder
и переадресацию вызова метода к этому экземпляру, вот метод:
// Illuminate\Database\Eloquent\Builder.php
/**
* Add a basic where clause to the query.
*
* @param string|array|\Closure $column
* @param mixed $operator
* @param mixed $value
* @param string $boolean
* @return $this
*/
public function where($column, $operator = null, $value = null, $boolean = 'and')
{
if ($column instanceof Closure) {
$column($query = $this->model->newModelQuery());
$this->query->addNestedWhereQuery($query->getQuery(), $boolean);
} else {
$this->query->where(...func_get_args());
}
return $this;
}