gpt4 book ai didi

php - PHP 和 Laravel 的特性

转载 作者:可可西里 更新时间:2023-10-31 22:44:01 25 4
gpt4 key购买 nike

我正在使用 Laravel 5.1,当模型之前的模型使用 appends 数组时,我想从 Trait 访问模型上的数组。

如果我的特征存在某些项目,我想将其添加到追加数组中。我不想为了实现这一点而编辑模型。特征在这种情况下是否真的可用,还是我应该使用继承?

array_push($this->appends, 'saucedByCurrentUser');

这是我当前设置的工作原理。

特质

<?php namespace App;

trait AwesomeSauceTrait {

/**
* Collection of the sauce on this record
*/
public function awesomeSauced()
{
return $this->morphMany('App\AwesomeSauce', 'sauceable')->latest();
}
public function getSaucedByCurrentUserAttribute()
{
if(\Auth::guest()){
return false;
}
$i = $this->awesomeSauced()->whereUserId(\Auth::user()->id)->count();
if ($i > 0){
return true;
}
return false;
}
}

型号

<?php namespace App;

use App\AwesomeSauceTrait;
use Illuminate\Database\Eloquent\Model;

class FairlyBlandModel extends Model {
use AwesomeSauceTrait;

protected $appends = array('age','saucedByCurrentUser');

}

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

trait AwesomeSauceTrait {
function __construct() {
parent::__construct();
array_push($this->appends, 'saucedByCurrentUser');
}
}

我有seen some workarounds for this ,但它们似乎都比手动将项目添加到数组更好/更干净。任何想法表示赞赏。

更新


我发现这种方法可以实现我对一个特征的需求,但它只适用于一个特征,而且我看不出使用它比继承有什么优势。

特质

protected $awesomeSauceAppends = ['sauced_by_current_user'];

protected function getArrayableAppends()
{
array_merge($this->appends, $this->awesomeSauceAppends);
parent::getArrayableAppends();
}

我目前如何处理我的模型,以及它的值(value)。

模型

public function __construct()
{
array_merge($this->appends, $this->awesomeSauceAppends);
}

最佳答案

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

同样,作为the PHP docs say :

If two Traits insert a method with the same name, a fatal error is produced, if the conflict is not explicitly resolved.

因此,它们不太适合您想要混契约(Contract)一行为的多个变体的情况,因为基本功能和混合功能无法以通用方式相互通信。

据我了解,您实际要解决的问题是:

  • 向 Eloquent 模型类添加自定义访问器和修改器
  • 将附加项添加到 protected $appends 数组以匹配这些方法

一种方法是继续使用 Traits,并使用 Reflection动态发现添加了哪些方法。但是,请注意 Reflection 以相当慢着称。

为此,我们首先实现一个带有循环的构造函数,我们可以通过以特定方式命名一个方法来 Hook 它。这可以放入它自己的 Trait 中(或者,您可以使用您自己的增强版本对 Eloquent Model 类进行子类化):

trait AppendingGlue {
public function __construct() {
// parent refers not to the class being mixed into, but its parent
parent::__construct();

// Find and execute all methods beginning 'extraConstruct'
$mirror = new ReflectionClass($this);
foreach ( $mirror->getMethods() as $method ) {
if ( strpos($method->getName(), 'extraConstruct') === 0 ) {
$method->invoke($this);
}
}
}
}

然后任意数量的 Traits 实现不同命名的 extraConstruct 方法:

trait AwesomeSauce {
public function extraConstructAwesomeSauce() {
$this->appends[] = 'awesome_sauce';
}

public function doAwesomeSauceStuff() {
}
}

trait ChocolateSprinkles {
public function extraConstructChocolateSprinkles() {
$this->appends[] = 'chocolate_sprinkles';
}

public function doChocolateSprinklesStuff() {
}
}

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

class BaseModel {
protected $appends = array('base');

public function __construct() {
echo "Base constructor run OK.\n";
}

public function getAppends() {
return $this->appends;
}
}

class DecoratedModel extends BaseModel {
use AppendingGlue, AwesomeSauce, ChocolateSprinkles;
}

$dm = new DecoratedModel;
print_r($dm->getAppends());

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

class ReDecoratedModel extends BaseModel {
use AppendingGlue, AwesomeSauce, ChocolateSprinkles;

protected $appends = ['switched_base'];
}

但是,如果您在混入 AppendingGlue 的同时重写构造函数,您确实需要做一些额外的工作,如 discussed in this previous answer .它类似于在继承情况下调用 parent::__construct,但您必须为特征的构造函数设置别名才能访问它:

class ReConstructedModel extends BaseModel {
use AppendingGlue { __construct as private appendingGlueConstructor; }
use AwesomeSauce, ChocolateSprinkles;

public function __construct() {
// Call the mixed-in constructor explicitly, like you would the parent
// Note that it will call the real parent as well, as though it was a grand-parent
$this->appendingGlueConstructor();

echo "New constructor executed!\n";
}
}

这可以通过继承一个类来避免,该类要么存在而不是 AppendingGlue 特性,要么已经使用它:

class GluedModel extends BaseModel {
use AppendingGlue;
}
class ReConstructedGluedModel extends GluedModel {
use AwesomeSauce, ChocolateSprinkles;

public function __construct() {
// Standard call to the parent constructor
parent::__construct();
echo "New constructor executed!\n";
}
}

这是一个 live demo of all of that put together .

关于php - PHP 和 Laravel 的特性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30922175/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com