我有一个Laravel项目,我正在从Laravel upgrade guide升级到5.3到5.4。
在指南中它说创建方法已经移动到Builder类,并且这个方法应该被称为新方法$model = static::query()->create($attributes);
。除了在升级指南中记录之外,互联网上还有许多问题,例如here和here。
我不明白的部分是为什么他们仍然将覆盖方法指定为静态。新的create方法不再是静态的(因此是新的调用),但是,所有示例仍然定义了一个静态方法来覆盖它。如果我这样做,PHPStorm会给我以下(预期)错误:
无法使非静态方法Builder-> create([attributes:array = []])静态
为什么示例(包含官方文档)将其覆盖为静态?
假设它适用于其他所有人的原因,为什么不开采工作呢?
所以这里有一个非常简短的解释,这里发生了什么。 5.3及更早版本中的Laravel雄辩模型在其自己的类中使用create
方法作为静态函数。这是来源:
public static function create(array $attributes = [])
{
$model = new static($attributes);
$model->save();
return $model;
}
同时该模型具有以下__call
定义。
public function __call($method, $parameters)
{
if (in_array($method, ['increment', 'decrement'])) {
return $this->$method(...$parameters);
}
return $this->newQuery()->$method(...$parameters);
}
这意味着将在Builder
对象的新实例上调用未在模型上定义的每个函数调用。
在5.4他们认为create
似乎更适合Builder
而不是模型本身所以他们在那里制作了这个方法:
public function create(array $attributes = [])
{
return tap($this->newModelInstance($attributes), function ($instance) {
$instance->save();
});
}
它基本上做同样的事情,但它更适合构建器,但是显着的区别是它不是静态的,因为模型上的所有类似静态的调用都被转发到Builder
实例。
如果你之前在子类中覆盖了方法,然后在某个时候调用了parent::create
,那么这可能不再有效,因为父级实际上没有创建,因此建议使用static::query()->create(...)
的替代代码。在实践中调用$this->__call('create', ...)
也可能会工作,但这很难阅读,并会搞乱IDE进行重构,因为它是一个无法察觉的调用Builder::create
。
现在最后一点是Model
也有@mixin Builder
。 @mixin
表示一个类基本上混合在当前类中以扩展其功能,并且用于向IDE提示当它以非标准OOP方式发生时(例如在这种情况下使用__call
和__callStatic
)。这导致你的IDE认为你在create
上超载Builder
由于IDE认为Builder
与Model
混在一起然而现实是它并没有完全混合而是混合在一起作为静力学(据我所知) PhpStorm处理这个概念有困难)
就是这样。我希望这是有道理的。