我使用的是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”;
}
}
这可以通过从一个类继承来避免,该类要么存在,要么已经使用了AppendingGlue
trait:
类GluedModel扩展了BaseModel{
使用附加胶;
}
类重构GluedModel扩展GluedModel{
使用冬虫夏草酱、巧克力粉;
公共函数构造(){
//对父构造函数的标准调用
父项::_构造();
echo“已执行新构造函数!\n”;
}
}
下面是所有这些内容的现场演示