私はちょうどこれに直面していました。元の投稿はかなり古いので、投稿されたときとは異なる場合がありますが、コンストラクターDIは機能しますが、かなり大きな注意事項があることがわかりました。
コードで次のトレイトを使用する場合:
<?php
namespace My\Module\Util;
use Psr\Log\LoggerInterface;
trait LoggerTrait
{
protected $logger;
public function __construct(
LoggerInterface $logger
) {
$this->logger = $logger;
}
/**
* @return Logger
*/
public function getLogger()
{
return $this->logger;
}
/**
* @param Logger $logger
*/
public function setLogger($logger)
{
$this->logger = $logger;
}
}
その後、クラスでその特性を使用します。
<?php
namespace My\Module;
use \My\Module\Util\LoggerTrait;
class Service
{
use LoggerTrait;
public function doSomething() {
$this->getLogger()->log('Something was done!');
}
}
ロガーインターフェイスは完全に注入され、すべてが正常に動作します。ただし、コンストラクターメソッドを使用して自分のクラスをServiceクラスに挿入する場合。例えば:
<?php
namespace My\Module;
use \My\Module\Util\LoggerTrait;
class Service
{
use LoggerTrait;
public function __construct(
\Some\Other\Class $class
) {
$this->other = $class;
}
public function doSomething() {
$this->getLogger()->log('Something was done!');
}
}
この場合、私の特性のコンストラクタメソッドが呼び出されることはありません。つまり、クラスの$ loggerプロパティが設定されることはありません。確かに私はトレイトをあまり使用していないので、私の知識はある程度制限されていますが、これは私のクラスがトレイトのコンストラクターメソッドをオーバーライドしたためであると想定しています。ほとんどのMagentoコードベースは、依存関係を注入するためにコンストラクターを使用し、トレイトでの使用を効果的に排除しているため、これはかなりショーストッパーです。
これに対して私が理解できる唯一の実際の解決策は、ObjectManagerを直接使用して、特性の依存関係を注入することです。
<?php
namespace My\Module\Util;
use Psr\Log\LoggerInterface;
trait LoggerTrait
{
protected $logger;
/**
* @return Logger
*/
public function getLogger()
{
if (is_null($this->logger)) {
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->logger = $objectManager->create('Psr\Log\LoggerInterface');
}
return $this->logger;
}
/**
* @param Logger $logger
*/
public function setLogger($logger)
{
$this->logger = $logger;
}
}
免責事項:MagentoでのObjectManagerの使用は一般的には推奨されませんが、私がこの例で見ることができることから、それが唯一の現実的なオプションです。私の例では、クラスに別のロガーインターフェイスを設定したい場合は、コンストラクターに注入し、クラスの$ loggerプロパティをオーバーライドすることで、それを行うことができます。