我有一个特征,专门负责哈希ID。
trait Hasher
{
protected $hasher;
public function __construct()
{
$salt = $this->hashSalt ?? null;
$length = $this->hashLength ?? null;
$chars = $this->hashChars ?? null;
$this->hasher = new Hashids($salt, $length, $chars);
parent::__construct(); // I hoped this would trigger MyModel's constructor
// but it doesn't work as expected.
}
}
我尝试在模型中使用它。
class MyModel extends Model
{
use Hasher;
private $hashSalt = 'Test';
private $hashChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
private $hashLength = 6;
}
这个主意是使它可重用,我不想将所有这些Hasher逻辑都写到我的模型中。
构造函数中的parent::__construct();
存在问题,导致MyModel
的构造函数无法触发,并且Model
的构造函数试图从Hasher
获取数据(据我所知)。 / p>
我知道我可以创建一个扩展Model并使用MyModel extends BaseModel
的新类,但是我不是扩展Model类的忠实拥护者。 (希望这不是唯一的方法)
您还有什么其他想法可以解决?
答案 0 :(得分:2)
您应该使用雄辩的引导程序/初始化程序。
trait Hasher
{
protected $hasher;
protected function initializeHasher()
{
$salt = $this->hashSalt ?? null;
$length = $this->hashLength ?? null;
$chars = $this->hashChars ?? null;
$this->hasher = new Hashids($salt, $length, $chars);
}
}
通过在您的特征initialize{traitName}
中实现一个方法,Laravel将在构造函数中自动调用它。如果您实现名为boot{traitName}
的静态方法,则会发生同样的事情,它将在您第一次使用模型时被调用。这是完整的解释
Illuminate\Database\Eloquent\Model::__construct
/**
* Create a new Eloquent model instance.
*
* @param array $attributes
* @return void
*/
public function __construct(array $attributes = [])
{
$this->bootIfNotBooted();
$this->initializeTraits();
$this->syncOriginal();
$this->fill($attributes);
}
这里有两点很重要,bootIfNotBooted
调用间接触发此方法
/**
* Boot all of the bootable traits on the model.
*
* @return void
*/
protected static function bootTraits()
{
$class = static::class;
$booted = [];
static::$traitInitializers[$class] = [];
foreach (class_uses_recursive($class) as $trait) {
$method = 'boot'.class_basename($trait);
if (method_exists($class, $method) && ! in_array($method, $booted)) {
forward_static_call([$class, $method]);
$booted[] = $method;
}
if (method_exists($class, $method = 'initialize'.class_basename($trait))) {
static::$traitInitializers[$class][] = $method;
static::$traitInitializers[$class] = array_unique(
static::$traitInitializers[$class]
);
}
}
}
您可以在这里注意到我之前解释的逻辑,调用了引导程序,并注册了初始化程序(但尚未调用)。 然后构造函数调用此
/**
* Initialize any initializable traits on the model.
*
* @return void
*/
protected function initializeTraits()
{
foreach (static::$traitInitializers[static::class] as $method) {
$this->{$method}();
}
}
这样,先前注册的每个初始化程序都会被调用。
答案 1 :(得分:1)
为什么不在trait中声明一个函数并在Model的构造函数中调用它,如下所示:
trait Hasher
{
protected $hasher;
public function hash()
{
$salt = $this->hashSalt ?? null;
$length = $this->hashLength ?? null;
$chars = $this->hashChars ?? null;
$this->hasher = new Hashids($salt, $length, $chars);
}
}
然后在模型的构造函数中:
class MyModel extends Model
{
use Hasher;
private $hashSalt = 'Test';
private $hashChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
private $hashLength = 6;
public function __construct()
{
$this->hash();
}
}