我的问题基于Data Viewer with Laravel 5.3 and Vue.js
这个家伙创建了一个特征DataViewer,其编码类似于以下内容:
trait DataViewer
{
// $query should be a Query Builder
public function scopePaginateAndOrder($query)
{
// Validation ...
// Where, Pagination, Order etc ...
return $query->where('foo', 'like', 'bar');
}
}
现在,您可以在任何Eloquent模型中使用此特征来添加搜索功能。
class Customer extends Model
{
use DataViewer;
}
一切都很平常,没什么特别的...... 但是有一些"魔法"我还没有在PHP中看到过。
在控制器中他执行类似
的操作$model = App\Customer::paginateAndOrder();
最后一段代码片段确实有许多我无法理解的方面。
感谢您的帮助!
答案 0 :(得分:1)
这是Laravel的魔力......根本不是php。
Laravel利用magic functions
所知的内容
- 为什么我可以使用::?
以静态方法方式调用这个非静态方法 醇>
我只会在这里列出两个__call()
和__callStatic()
,当你分别调用不存在的非静态静态函数时会调用这些函数。
所以在Illuminate\Database\Eloquent\Model
这是所有模型的超类都这样做,请检查link。
- 为什么我可以省略方法名称中的范围?'
醇>
Simply Laravel允许您省略表示其功能的函数名称的前缀。例如。在您的情况下scope
前缀..并继续按特定顺序添加前缀,直到找到它为止。
如果您需要仔细查看,请阅读code。
- 我不必将Query Builder对象作为参数传递。那么特质如何知道"我希望在哪个模型上分页/订购
醇>
我认为这是由于Laravel IoC容器和依赖注入......
注意:Q3需要更多的研究才能确定&如何注射。
答案 1 :(得分:1)
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
。
希望这有帮助!