扩展特征与自身冲突

Extending a trait conflicts with itself

我正在尝试扩展特征。我的意思是创建一个特征,为不同的特征重新定义几个方法。

这是我的代码(PHP 5.6 和 Laravel 5.4):

namespace App\Traits;

use Illuminate\Database\Eloquent\Concerns\HasTimestamps;

trait ExtendHasTimestamps
{
    use HasTimestamps {
        HasTimestamps::setCreatedAt as parentSetCreatedAt;
        HasTimestamps::setUpdatedAt as parentSetUpdatedAt;
    }

    public function setCreatedAt($value) {
        if ($value !== '') return $this;
        return $this->parentSetCreatedAt($value);
    }

    public function setUpdatedAt($value) {
        if ($value !== '') return $this;
        return $this->parentSetUpdatedAt($value);
    }
}

当我在模型中使用 ExtendHasTimestamps 时出现问题,它与 HasTimestamps 冲突,因为 Eloquent\Modeluse HasTimestamps。在 PHP 7 之前,如果您尝试定义相同的 属性 两次,traits 会抛出致命错误。因此,由于我在 HasTimestamps 中定义了 $timestamps,并且借助 use HasTimestamps 通过 ExtendHasTimestamps 再次定义了 $timestamps,因此它中断了。

简而言之:

trait HasTimestamps {
    protected $timestamps = true; //problematic property
}

trait ExtendHasTimestamps {
    use HasTimestamps;
    // add validation then call HasTimestamps method
}

class Model {
    use HasTimestamps;
}

class MyModel extends Model {
    use ExtendHasTimestamps; //everything breaks
}

有没有办法让 PHP 相信它确实是同一件事并且它可以停止与自己发生冲突,或者通知 class 我正在使用(的扩展Eloquent\Model) 停止使用 HasTimestamps 来支持我的特质?


This question 没有回答我的,因为我正在尝试使用一个特征来覆盖另一个特征,而不是仅仅向每个 class 我需要使用它的地方添加方法代码.

在我看来,您实际上并不需要首先扩展特征。我会简单地重写 child class 中使用的特征中的方法,然后调用特征中的 parent 方法。

演示:https://3v4l.org/2DqZQ

<?php

trait HasTimestamps
{
    protected $timestamps = true;

    public function setCreatedAt($value)
    {
        echo 'HasTimestamps::setCreatedAt'.PHP_EOL;
        return $this;
    }

    public function setUpdatedAt($value)
    {
        echo 'HasTimestamps::setUpdatedAt'.PHP_EOL;
        return $this;
    }
}

trait ExtendHasTimestamps
{
    public function setCreatedAt($value)
    {
        echo 'ExtendHasTimestamps::setCreatedAt'.PHP_EOL;

        if ($value !== '') return $this;

        return parent::setCreatedAt($value);
    }

    public function setUpdatedAt($value)
    {
        echo 'ExtendHasTimestamps::setUpdatedAt'.PHP_EOL;

        if ($value !== '') return $this;

        return parent::setUpdatedAt($value);
    }
}

class Model
{
    use HasTimestamps;
}

class MyModel extends Model
{
    use ExtendHasTimestamps;
}

(new MyModel)->setCreatedAt('');

echo PHP_EOL;

(new MyModel)->setCreatedAt('time');

ExtendHasTimestamps::setCreatedAt
HasTimestamps::setCreatedAt

ExtendHasTimestamps::setCreatedAt