扩展Laravel create():为什么文档说将非静态方法覆盖为静态方法?



我有一个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 认为BuilderModel混合在一起,但现实情况是它并没有完全混合在一起,而是作为静态混合在一起(据我所知,PhpStorm 在处理这个概念时遇到了麻烦)

原来如此。我希望这是有道理的。

最新更新