我有一个Laravel项目,我正在按照Laravel升级指南从5.3升级到5.4。
在指南中,它说创建方法已移至 Builder 类,并且此方法应称为新方式$model = static::query()->create($attributes);
。 除了记录在升级指南中之外,互联网上还有很多问题,例如这里和这里。
我不明白的部分是为什么他们仍然将覆盖方法指定为静态。 新的 create 方法不再是静态的(因此是新的调用),但是,所有示例仍然定义一个静态方法来覆盖它。 如果我这样做,PHPStorm 会给我以下(预期的)错误:
无法使非静态方法 Builder->create([属性: 数组 = []]) 静态
为什么示例(包括官方文档)将其覆盖为静态?
假设它对其他人有用是有原因的,为什么我的不起作用?
所以这里有一个非常简短的解释来解释这里发生的事情。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 认为您正在Builder
上重载create
,因为 IDE 认为Builder
与Model
混合在一起,但现实情况是它并没有完全混合在一起,而是作为静态混合在一起(据我所知,PhpStorm 在处理这个概念时遇到了麻烦)
原来如此。我希望这是有道理的。