Laravel 在特征构造函数中传递参数
Laravel pass arguments in trait constructor
我有一个 TimezoneTrait
用于 User
模型。我还有一个 UserRepositoryInterface
,它是通过服务提供商加载的,并且在所有 类 上都能正常工作,所以绑定应该没问题:
public function register()
{
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}
public function provides()
{
return [
UserRepositoryInterface::class,
];
}
现在我遇到的问题是我必须在我的特征中使用那个存储库,所以我自然而然地这样做了:
private $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
但是转储显示存储库是 null
。 traits不能注入依赖吗?
在 trait 中定义 __constructor
实际上是错误的。或者只是一个糟糕的设计。 Constructors should be specific to a class to which they belong, not traits. Another issue then, you're importing trait in Model class, that means you should specifically follow its rule about how a trait in a model is loaded.
在模型的 boot
ing 阶段,它在 class 中递归搜索导入的特征,并自动静态调用使用 boot{TraitNameHere}
命名约定的方法。这证明模型中的特征不涉及 Laravel 的依赖注入周期。
要做到这一点,您可以使用 Laravel 全局帮助程序将存储的实例加载到容器中,就像外观 App::make(DefinedKeyHere)
一样。然后将分配的实例存储到一个 static 属性 中以使其保留到运行时结束并且因为调用方法是 static
.
trait TimezoneTrait
{
protected static $userRepository;
protected static function bootTimezoneTrait()
{
static::$userRepository = \App::make(UserRepositoryInterface::class);
}
}
如果您当前正在尝试避免使用全局帮助程序,则监听模型启动事件也很有帮助。 EventServiceProvider 中的示例,
Event::listen('eloquent.booting:*', function (Model $model) {
$model->setUserRepository($this->app[UserRepositoryInterface::class]);
});
那么特征就是,
trait TimezoneTrait
{
protected static $userRepository;
public function static setUserRepository(UserRepositoryInterface $userRepository)
{
static::$userRepository = $userRepository;
}
}
请注意,我将 setUserRepository
定义为静态的,但您也可以将其设置为非静态的。
为了进一步了解模型事件,模型在执行相关操作时会触发多个事件。
来自 Laravel 5.5、
的示例事件
public function getObservableEvents()
{
return array_merge(
[
'creating', 'created', 'updating', 'updated',
'deleting', 'deleted', 'saving', 'saved',
'restoring', 'restored',
],
$this->observables
);
}
以及其他两个在实例化(也未序列化)时触发的默认事件,它们是 booting
和 booted
。以及用于触发事件的方法,请注意事件名称。
protected function fireModelEvent($event, $halt = true)
{
// ...
return ! empty($result) ? $result : static::$dispatcher->{$method}(
"eloquent.{$event}: ".static::class, $this
);
}
我有一个 TimezoneTrait
用于 User
模型。我还有一个 UserRepositoryInterface
,它是通过服务提供商加载的,并且在所有 类 上都能正常工作,所以绑定应该没问题:
public function register()
{
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}
public function provides()
{
return [
UserRepositoryInterface::class,
];
}
现在我遇到的问题是我必须在我的特征中使用那个存储库,所以我自然而然地这样做了:
private $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
但是转储显示存储库是 null
。 traits不能注入依赖吗?
在 trait 中定义 __constructor
实际上是错误的。或者只是一个糟糕的设计。 Constructors should be specific to a class to which they belong, not traits. Another issue then, you're importing trait in Model class, that means you should specifically follow its rule about how a trait in a model is loaded.
在模型的 boot
ing 阶段,它在 class 中递归搜索导入的特征,并自动静态调用使用 boot{TraitNameHere}
命名约定的方法。这证明模型中的特征不涉及 Laravel 的依赖注入周期。
要做到这一点,您可以使用 Laravel 全局帮助程序将存储的实例加载到容器中,就像外观 App::make(DefinedKeyHere)
一样。然后将分配的实例存储到一个 static 属性 中以使其保留到运行时结束并且因为调用方法是 static
.
trait TimezoneTrait
{
protected static $userRepository;
protected static function bootTimezoneTrait()
{
static::$userRepository = \App::make(UserRepositoryInterface::class);
}
}
如果您当前正在尝试避免使用全局帮助程序,则监听模型启动事件也很有帮助。 EventServiceProvider 中的示例,
Event::listen('eloquent.booting:*', function (Model $model) {
$model->setUserRepository($this->app[UserRepositoryInterface::class]);
});
那么特征就是,
trait TimezoneTrait
{
protected static $userRepository;
public function static setUserRepository(UserRepositoryInterface $userRepository)
{
static::$userRepository = $userRepository;
}
}
请注意,我将 setUserRepository
定义为静态的,但您也可以将其设置为非静态的。
为了进一步了解模型事件,模型在执行相关操作时会触发多个事件。
来自 Laravel 5.5、
的示例事件public function getObservableEvents()
{
return array_merge(
[
'creating', 'created', 'updating', 'updated',
'deleting', 'deleted', 'saving', 'saved',
'restoring', 'restored',
],
$this->observables
);
}
以及其他两个在实例化(也未序列化)时触发的默认事件,它们是 booting
和 booted
。以及用于触发事件的方法,请注意事件名称。
protected function fireModelEvent($event, $halt = true)
{
// ...
return ! empty($result) ? $result : static::$dispatcher->{$method}(
"eloquent.{$event}: ".static::class, $this
);
}