Laravel很好地利用了PHP的一些神奇方法,特别是在这种情况下__call()
和__callStatic
。
http://php.net/manual/en/language.oop5.overloading.php#object.callstatic
随着callStatic
,如果一个静态方法调用时或者不存在,或者是不可访问的,则呼叫将被委派给该类别的__callStatic()
方法(如果有的话)。 __call()
和实例方法也是如此。
如果您在Illuminate\Database\Eloquent\Model
看,你会发现:
/**
* Handle dynamic method calls into the model.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
if (in_array($method, ['increment', 'decrement'])) {
return call_user_func_array([$this, $method], $parameters);
}
$query = $this->newQuery();
return call_user_func_array([$query, $method], $parameters);
}
/**
* Handle dynamic static method calls into the method.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public static function __callStatic($method, $parameters)
{
$instance = new static;
return call_user_func_array([$instance, $method], $parameters);
}
在上面,如果__callStatic
被调用,然后它会创建模型的实例new
并尝试调用该实例的方法,所以当您拨打App\Customer::paginateAndOrder()
时,它会尝试拨打paginateAndOrder()
作为实例方法。
(不包括increment
和decrement
)模型上的__call()
方法将尝试在Illuminate\Database\Eloquent\Builder
上调用该方法。 Builder
则有它自己的__call()
方法已在它下面:
if (method_exists($this->model, $scope = 'scope' . ucfirst($method))) {
return $this->callScope([$this->model, $scope], $parameters);
}
callScope
然后只需调用实际scopePaginateAndOrder
并传递Builder
通过。
希望这会有所帮助!
'我不必将查询生成器对象作为参数传递,'//查询应该是查询生成器'是不好的做法(应该/可以/ ...)。为什么函数不是这样的:'public function scopePaginateAndOrder(QueryBuilder $ query = null)'?在'1.'上,它会在php'严格标准:非静态方法'中抛出一个注释/警告,但是这个方法将被调用。用'2'来表示什么意思? – JustOnUnderMillions
顺便说一句:一旦你谈到'scopePaginateAndOrder'那么关于'paginateAndOrder',就会有2个diff。方法调用,不一样。所以当你尝试调用scopePaginateAndOrder()时,你不能忽略'范围'。你的逻辑中出现其他问题。 – JustOnUnderMillions
好吧,不是键入提示参数确实是一个不好的做法,我只是从上面的链接视频做了一个复制和粘贴。是的,我必须使用paginateAndOrder()INSTEAD scopePaginateAndOrder(),否则它会抛出一个异常 – Qobus