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

时间:2019-03-04 16:45:15

标签: php laravel upgrade

我有一个Laravel项目,我正在按照Laravel upgrade guide从5.3升级到5.4。

在指南中,它说创建方法已移至Builder类,并且该方法应称为新方法$model = static::query()->create($attributes);。除了升级指南中记录的内容外,互联网上还有很多问题,例如herehere

我不了解的部分是为什么他们仍然将覆盖方法指定为静态方法。新的create方法不再是静态的(因此进行了新的调用),但是所有示例仍然定义了一个静态方法来覆盖它。如果这样做,PHPStorm会给我以下(预期)错误:

  

无法使非静态方法Builder-> create([attributes:array = []])静态

为什么示例(包括官方文档)将其覆盖为静态?

假设有一个对其他所有人都有效的原因,为什么我的工作不成功?

1 个答案:

答案 0 :(得分:0)

因此,这里有一个简短的解释。 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();
    });
}

它基本上具有相同的作用,但更适合构建器,但是显着的区别是它不是静态的,因为模型上所有类似静态的调用都被转发到{{1 }} 实例

如果您之前确实在子类中重写了该方法,然后在某个时候调用了Builder,由于父级实际上没有创建对象,因此这可能不再起作用,因此,parent::create的替代代码被建议。在实践中,调用static::query()->create(...)也可能会起作用,但这很难读,并且由于无法调用$this->__call('create', ...)而使IDE进行重构,因此很麻烦。

现在最后一点是Builder::create上也有Model@mixin Builder表示一个类在当前类中基本上是混合在一起的,以扩展其功能,并用于向IDE暗示当它以非标准OOP方式发生时(例如,@mixin__call)。这导致您的IDE认为您正在__callStaticcreate上超载,这是因为IDE认为BuilderBuilder混合在一起,但实际情况并非如此。完全混为一谈,而是混为一谈(据我所知,PhpStorm在处理这个概念时遇到了麻烦)

就这样。我希望这是有道理的。