Illuminate\Database\Eloquent\Model; // 业务表基类
Illuminate\Database\Eloquent\Relations\Pivot;// 关联中间表基类
最近在设计新项目的Laravel Model时,因为业务表Dao与关联表Dao采用了不同的基类,我们希望拥有一个共同的父类进行Dao层的统一封装,遂建立了所有的Dao共用的Trait.
// 公用Trait
trait Common
{
public $keyType = 'bigint';
}
// 业务表Dao基类
class Base extends Model
{
use Common;
}
很不幸的是,这样出现了Fatal Error.
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_UNKNOWN)
Illuminate\Database\Eloquent\Model and App\Models\Traits\Common define the same property ($keyType) in the composition of App\Models\Base. However, the definition differs and is considered incompatible. Class was composed
查看官方文档(http://www.php.net/manual/zh/language.oop5.traits.php),官方有解释:
Trait 定义了一个属性后,类就不能定义同样名称的属性,否则会产生 fatal error。 有种情况例外:属性是兼容的(同样的访问可见度、初始默认值)。 在 PHP 7.0 之前,属性是兼容的,则会有 E_STRICT 的提醒。
需要注意的是,trait的属性与方法不同,不能通过trait直接重写基类,trait中的属性可见度、默认值都必须与继承它的类相同。 简单的例子:
class Model
{
public $key = 'a';
}
trait Common
{
public $key = 'b';
}
class Node extends Model
{
use Common;
public function output()
{
echo $this->key . "\n";
}
}
$node = new Node();
$node->output(); // fatal error
这样会抛出致命错误,如果我们修改Node类加入对$this->key 的定义,并与trait Common一致,则冲突被解决。
class Node extends Model
{
use Common;
public $key = 'b';
public function output()
{
echo $this->key . "\n";
}
}
综上所述,trait无法直接通过覆盖属性的方式修改基类属性,可以考虑通过构造函数加入调用trait中的初始化方法来解决。