这段代码如何以及为何起作用?
How and why does this code work?
我的问题是基于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;
}
一切都很平常,没什么特别的...
但是还有一些 "magic" 我还没有在 PHP 中看到。
在控制器中他做了类似
的事情
$model = App\Customer::paginateAndOrder();
最后一个代码片段确实有很多我无法理解的方面。
- 为什么我可以使用 :: 以静态方法的方式调用这个非静态方法?
- 为什么我可以从方法名称中省略 scope?
- 我不必将查询生成器对象作为参数传递。那么我想要 paginate/order
的特征 "know" 如何
感谢大家的帮助!
这就是 Laravel 的魔力.. 根本不是 php。
Laravel 利用了 magic functions
的已知信息
- Why can i call this non-static-method in a static-method way using ::?
我这里只列出两个__call()
和__callStatic()
,这两个函数分别在调用non-existentnon-static静态函数时被调用..
所以在 Illuminate\Database\Eloquent\Model
中,它是所有模型的超级 class,检查这个 link。
- Why can i omit the scope from the method name?'
简单地 Laravel 允许您省略代表其功能的函数名称的前缀。例如。 scope
前缀在你的情况下..并继续以特定顺序添加前缀直到找到它。
如果您想进一步了解,请阅读 code。
- I don't have to pass a Query Builder object as parameter. So how does the trait "know" on which model i want to paginate/order
我认为这是由于 Laravel IoC 容器和依赖注入..
注意:第 3 季度需要更多的研究来确定注射的时间和方式。
Laravel 很好地利用了 PHP 的一些神奇方法,特别是在本例中 __call()
和 __callStatic
.
http://php.net/manual/en/language.oop5.overloading.php#object.callstatic
使用 callStatic
,如果调用的静态方法不存在或不可访问,则调用将委托给 class 中的 __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
。
希望对您有所帮助!
我的问题是基于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;
}
一切都很平常,没什么特别的... 但是还有一些 "magic" 我还没有在 PHP 中看到。
在控制器中他做了类似
的事情$model = App\Customer::paginateAndOrder();
最后一个代码片段确实有很多我无法理解的方面。
- 为什么我可以使用 :: 以静态方法的方式调用这个非静态方法?
- 为什么我可以从方法名称中省略 scope?
- 我不必将查询生成器对象作为参数传递。那么我想要 paginate/order 的特征 "know" 如何
感谢大家的帮助!
这就是 Laravel 的魔力.. 根本不是 php。
Laravel 利用了 magic functions
的已知信息
- Why can i call this non-static-method in a static-method way using ::?
我这里只列出两个__call()
和__callStatic()
,这两个函数分别在调用non-existentnon-static静态函数时被调用..
所以在 Illuminate\Database\Eloquent\Model
中,它是所有模型的超级 class,检查这个 link。
- Why can i omit the scope from the method name?'
简单地 Laravel 允许您省略代表其功能的函数名称的前缀。例如。 scope
前缀在你的情况下..并继续以特定顺序添加前缀直到找到它。
如果您想进一步了解,请阅读 code。
- I don't have to pass a Query Builder object as parameter. So how does the trait "know" on which model i want to paginate/order
我认为这是由于 Laravel IoC 容器和依赖注入..
注意:第 3 季度需要更多的研究来确定注射的时间和方式。
Laravel 很好地利用了 PHP 的一些神奇方法,特别是在本例中 __call()
和 __callStatic
.
http://php.net/manual/en/language.oop5.overloading.php#object.callstatic
使用 callStatic
,如果调用的静态方法不存在或不可访问,则调用将委托给 class 中的 __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
。
希望对您有所帮助!