PHP和Laravel的特性

我使用的是Laravel 5.1,当模型之前的模型使用附录数组时,我希望从Trait访问模型上的数组

如果我的trait中存在appends数组,我想将它添加到appends数组中。我不想为了实现这一点而编辑模型。在这个场景中,特征真的可用吗?还是应该使用继承

array\u push($this->追加'saucedByCurrentUser');

下面是我当前设置的工作原理

特质

<?php命名空间应用程序;
性状冬虫夏草{
/**
*这张唱片上的酱汁收藏
*/
公共功能
{
返回$this->morpmany('App\awesomesaint','sauceable')->latest();
}
公共函数getSaucedByCurrentUserAttribute()
{
如果(\Auth::guest()){
返回false;
}
$i=$this->awesomeSauced()->whereUserId(\Auth::user()->id)->count();
如果($i>0){
返回true;
}
返回false;
}
}

型号

<?php命名空间应用程序;
使用App\AwesomeSauceTrait;
使用Illumb\Database\Elount\Model;
类FairlyBlandModel扩展了该模型{
使用冬虫夏草;
受保护的$appends=array('age','saucedByCurrentUser');
}

我想做的是实现与扩展类相同的效果。我有一些相似的特性,所以使用继承有点难看

trait AwesomeSauceTrait{
函数_u构造(){
父项::_构造();
数组推送($this->追加'saucedByCurrentUser');
}
}

我已经看到了一些解决方法,但是没有一个比手动将项目添加到数组更好/更干净。欢迎提出任何意见

更新


我发现这种方法可以实现我对一种特性的需求,但它只对一种特性有效,我不认为使用这种方法比遗传有什么好处

特质

受保护的$awesomeSauceAppends=['sauced'u by'u current'u user'];
受保护函数getArrayableAppends()
{
数组合并($this->appends,$this->awesomeSauceAppends);
父::getArrayableAppends();
}

我目前是如何处理我的模型的,不管它值多少钱

型号

公共功能\uuuu构造()
{
数组合并($this->appends,$this->awesomeSauceAppends);
}

特征有时被描述为“编译器辅助的复制和粘贴”;使用Trait的结果总是可以以有效类的形式写出来。因此,在一个Trait中没有parent的概念,因为一旦应用了Trait,它的方法就无法与类本身中定义的或同时从其他Trait导入的方法区分开来

类似地,正如PHP文档所说:

如果两个Traits插入一个同名的方法,如果冲突没有显式解决,则会产生致命错误

因此,它们不太适合于您希望混合同一行为的多个变体的情况,因为基本功能和混合功能无法以通用方式相互对话

据我所知,你实际上要解决的问题是:

  • 向雄辩的模型类添加自定义访问器和变体
  • 将其他项添加到与这些方法匹配的受保护的$appends数组中

一种方法是继续使用Traits,并使用反射动态发现添加了哪些方法。然而,要注意,反射的速度相当慢

为此,我们首先用一个循环实现一个构造函数,我们只需以特定的方式命名一个方法,就可以将其钩住。这可以放在它自己的特性中(或者,你可以用你自己的增强版对雄辩的模型类进行子分类):

特性附加胶{
公共函数构造(){
//父类不是指要混入的类,而是指其父类
父项::_构造();
//查找并执行从“extraConstruct”开始的所有方法
$mirror=新的ReflectionClass($this);
foreach($mirror->getMethods()作为$method){
if(strpos($method->getName(),'extraConstruct')==0){
$method->invoke($this);
}
}
}
}

然后,任何数量的特征实现不同的命名extraConstruct方法:

trait awesomesaint{
公共功能外部结构WesomeSauce(){
$this->追加[]=“很棒的酱汁”;
}
公共功能DOAWESOMESAUCESTAFF(){
}
}
特色巧克力{
公共函数ExtraconstructchocolateSpreadys(){
$this->追加[]='chocolate_springs';
}
公共职能部门{
}
}

最后,我们将所有特征混合到一个普通模型中,并检查结果:

类基本模型{
受保护的$appends=数组('base');
公共函数构造(){
echo“基本构造函数运行正常。\n”;
}
公共函数getAppends(){
返回$this->appends;
}
}
类DecoratedModel扩展了BaseModel{
使用胶水、虫草酱、巧克力粉;
}
$dm=新装饰模型;
打印($dm->getAppends());

我们可以在装饰模型本身内部设置$appends的初始内容,它将替换BaseModel定义,但不会中断其他特性:

类重新装饰模型扩展了BaseModel{
使用胶水、虫草酱、巧克力粉;
受保护的$appends=['switched_base'];
}

但是,如果您在混合AppendingGlue的同时过度使用构造函数,您确实需要做一些额外的工作,正如前面的回答中所讨论的。这类似于在继承情况下调用parent::u construct,但您必须别名trait的构造函数才能访问它:

类重构模型扩展了BaseModel{
使用AppendingGlue{uuu构造作为私有appendingGlueConstructor;}
使用冬虫夏草酱、巧克力粉;
公共函数构造(){
//显式调用mixed-in构造函数,就像调用父构造函数一样
//注意,它也会调用真实的父对象,就像它是一个祖父母一样
$this->appendingGlueConstructor();
echo“已执行新构造函数!\n”;
}
}

这可以通过从一个类继承来避免,该类要么存在,要么已经使用了AppendingGluetrait:

类GluedModel扩展了BaseModel{
使用附加胶;
}
类重构GluedModel扩展GluedModel{
使用冬虫夏草酱、巧克力粉;
公共函数构造(){
//对父构造函数的标准调用
父项::_构造();
echo“已执行新构造函数!\n”;
}
}

下面是所有这些内容的现场演示

发表评论