如何在 Yii2 配置中注入 class 依赖?
how to inject class dependency in Yii2 configuration?
我正在学习Yii2。这是一种我没有用谷歌搜索答案的情况。
我在 config/console.php
的 $config['components']
数组中注册了一个名为 scraper
的组件,
这个 scraper
class 有一个 public 属性 $_client
这是一个 Goutte\Client
class。
我尝试使用下面的方式来设置scraper
组件,但它不起作用,Yii2没有将$_client
实例化为Goutte\Client
对象。
$config = [
'scraper' => [
'class' => 'app\models\Scraper',
'_pageSize' => 10,
'_client' => [ //not working. can not instantiate this property as an object
'class' => 'Goutte\Client'
],
],
//...
]
问题:在配置中注入依赖项的工作方式是什么?
Yii2 不会实例化配置数组中第一层以外的对象。换句话说,scraper
将被实例化为一个对象,但它的 属性 _client
将被实例化为一个数组 ['class' => 'Goutte\Client']
.
你应该自己实现这个逻辑:
class Service extends Component
{
private $_client = null;
public $clientClass;
public function getClient()
{
if (null !== $this->_client) {
return $this->_client;
}
$this->_client = new $clientClass;
return $this->_client;
}
}
或者,您可以将 Goutte\Client
注册为一个单独的组件,然后 Yii 将正确地实例化它。
更新:
澄清一下,从配置中实例化对象是使用 yii\base\Configurable
接口完成的,该接口在 yii\base\Object
class 中实现。最终,这个实现执行 Yii::configure
:
public static function configure($object, $properties)
{
foreach ($properties as $name => $value) {
$object->$name = $value;
}
return $object;
}
如您所见,所有属性都将被赋予各自的值,因此 _client
将成为一个数组,而不是一个对象。
在guide itself: The property targets of the class yii\log\Dispatcher can be initialized with a class names or an objects. To make it working as one expects the init方法中发现另一种方法被覆盖:
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
foreach ($this->targets as $name => $target) {
if (!$target instanceof Target) {
$this->targets[$name] = Yii::createObject($target);
}
}
}
这允许 configuration/initialization 这样的日志组件:
'log' => [
'class' => 'yii\log\Dispatcher',
'targets' => [
[
'class' => 'yii\log\FileTarget',
],
],
],
注意:这里的targets是一个数组。但它也可以用一个 class/object 来完成。
所以在你的情况下,这应该是一个解决方案:
namespace app\models;
class Scraper extends ActiveRecord // or extends from anything that actually implements yii\base\Configurable
{
public $_client;
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
if (!$this->_client instanceof Goutte\Client) {
$this->_client = Yii::createObject($this->_client);
}
}
}
顺便说一句:变量名中的下划线前缀通常用于私有属性。
我正在学习Yii2。这是一种我没有用谷歌搜索答案的情况。
我在 config/console.php
的 $config['components']
数组中注册了一个名为 scraper
的组件,
这个 scraper
class 有一个 public 属性 $_client
这是一个 Goutte\Client
class。
我尝试使用下面的方式来设置scraper
组件,但它不起作用,Yii2没有将$_client
实例化为Goutte\Client
对象。
$config = [
'scraper' => [
'class' => 'app\models\Scraper',
'_pageSize' => 10,
'_client' => [ //not working. can not instantiate this property as an object
'class' => 'Goutte\Client'
],
],
//...
]
问题:在配置中注入依赖项的工作方式是什么?
Yii2 不会实例化配置数组中第一层以外的对象。换句话说,scraper
将被实例化为一个对象,但它的 属性 _client
将被实例化为一个数组 ['class' => 'Goutte\Client']
.
你应该自己实现这个逻辑:
class Service extends Component
{
private $_client = null;
public $clientClass;
public function getClient()
{
if (null !== $this->_client) {
return $this->_client;
}
$this->_client = new $clientClass;
return $this->_client;
}
}
或者,您可以将 Goutte\Client
注册为一个单独的组件,然后 Yii 将正确地实例化它。
更新:
澄清一下,从配置中实例化对象是使用 yii\base\Configurable
接口完成的,该接口在 yii\base\Object
class 中实现。最终,这个实现执行 Yii::configure
:
public static function configure($object, $properties)
{
foreach ($properties as $name => $value) {
$object->$name = $value;
}
return $object;
}
如您所见,所有属性都将被赋予各自的值,因此 _client
将成为一个数组,而不是一个对象。
在guide itself: The property targets of the class yii\log\Dispatcher can be initialized with a class names or an objects. To make it working as one expects the init方法中发现另一种方法被覆盖:
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
foreach ($this->targets as $name => $target) {
if (!$target instanceof Target) {
$this->targets[$name] = Yii::createObject($target);
}
}
}
这允许 configuration/initialization 这样的日志组件:
'log' => [
'class' => 'yii\log\Dispatcher',
'targets' => [
[
'class' => 'yii\log\FileTarget',
],
],
],
注意:这里的targets是一个数组。但它也可以用一个 class/object 来完成。
所以在你的情况下,这应该是一个解决方案:
namespace app\models;
class Scraper extends ActiveRecord // or extends from anything that actually implements yii\base\Configurable
{
public $_client;
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
if (!$this->_client instanceof Goutte\Client) {
$this->_client = Yii::createObject($this->_client);
}
}
}
顺便说一句:变量名中的下划线前缀通常用于私有属性。