AuraPHP DI 动态 class 或基于决策的注入
AuraPHP DI dynamic class or decision based injection
我是现代依赖注入方法的新手,我正在尝试弄清楚如何让方法根据条件选择 class 要使用的方法。我打赌我已经关闭了我的设计结构,但我也没有看到如何通过配置在 Aura DI 中执行此操作。
这是我的 Aura 配置
<?php
namespace Aura\Cli_Project\_Config;
use Aura\Di\Config;
use Aura\Di\Container;
class Common extends Config {
public function define(Container $di) {
// utilities
$di->set(
'App\Inventory\Utilities\EmailParser',
$di->newInstance('App\Inventory\Utilities\PlancakeParser')
);
// commands
$di->params['App\Inventory\Command\IncomingOrder'] = array(
'stdio' => $di->lazyGet('aura/cli-kernel:stdio'),
'parser' => $di->get('App\Inventory\Utilities\EmailParser')
);
}
// ...
}
这是有问题的 class,它需要根据它找到的 "source" 使用不同的 classes。
<?php
namespace App\Inventory\Command;
use Aura\Cli\Stdio;
use App\Inventory\Utilities\EmailParser;
use App\Inventory\Sources\Etsy;
use App\Inventory\Sources\Amazon;
use App\Inventory\Sources\Ebay;
class IncomingOrder {
public function __construct(
Stdio $stdio,
EmailParser $parser) {
$this->stdio = $stdio;
$this->parser = $parser;
}
public function process() {
// other code to parse message
// source is set by determining where it came from
$source = 'Etsy';
switch($source) {
case 'Etsy' :
// This bit seems really wrong
$sourceParser = new Etsy\OrderParser();
break;
case 'Amazon' :
$sourceParser = new Amazon\OrderParser();
break;
case 'Ebay' :
$sourceParser = new Ebay\OrderParser();
break;
default :
$sourceParser = null;
}
// Do source specific processing
}
}
我是否需要在确定源后立即拆分我的处理,以便可以使用该源作为参数初始化新的 class?
我在配置中看到的唯一方法是对 return 正确的源 class 执行一个惰性匿名函数,但这也违背了现代设计原则。
我想澄清的是,您不需要像这里的许多 di 容器那样使用 set
方法。可以修改代码为
<?php
namespace Aura\Cli_Project\_Config;
use Aura\Di\Config;
use Aura\Di\Container;
class Common extends Config
{
public function define(Container $di)
{
// commands
$di->params['App\Inventory\Command\IncomingOrder'] = array(
'stdio' => $di->lazyGet('aura/cli-kernel:stdio'),
'parser' => $di->lazyNew('App\Inventory\Utilities\EmailParser')
);
}
// ...
}
当您想将同一个对象传递给许多其他对象时,可以使用 set
。不要使用 newInstance
因为它会在调用时创建对象。您可能需要使用 lazyNew
或 lazyGet
功能。
关于您关于动态决策的问题。这是我的想法,我之前确实遇到过这个问题。但是没有看到我做了什么,所以 iirc 我所做的是向 IncomingOrder
class 注入一个可以创建对象的工厂。这样做的好处是,如果您的源解析需要某种依赖,您可以在工厂内部使用 di。
例如:
<?php
namespace Something;
use Aura\Di\Container;
class SourceFactory
{
public function __construct(Container $di)
{
$this->di = $di;
}
public function newInstance($source)
{
if ($di->has($source)) {
return $di->get($source);
}
// or alternatively create with new as done in switch
}
}
希望对您有所帮助。
谢谢
我是现代依赖注入方法的新手,我正在尝试弄清楚如何让方法根据条件选择 class 要使用的方法。我打赌我已经关闭了我的设计结构,但我也没有看到如何通过配置在 Aura DI 中执行此操作。
这是我的 Aura 配置
<?php
namespace Aura\Cli_Project\_Config;
use Aura\Di\Config;
use Aura\Di\Container;
class Common extends Config {
public function define(Container $di) {
// utilities
$di->set(
'App\Inventory\Utilities\EmailParser',
$di->newInstance('App\Inventory\Utilities\PlancakeParser')
);
// commands
$di->params['App\Inventory\Command\IncomingOrder'] = array(
'stdio' => $di->lazyGet('aura/cli-kernel:stdio'),
'parser' => $di->get('App\Inventory\Utilities\EmailParser')
);
}
// ...
}
这是有问题的 class,它需要根据它找到的 "source" 使用不同的 classes。
<?php
namespace App\Inventory\Command;
use Aura\Cli\Stdio;
use App\Inventory\Utilities\EmailParser;
use App\Inventory\Sources\Etsy;
use App\Inventory\Sources\Amazon;
use App\Inventory\Sources\Ebay;
class IncomingOrder {
public function __construct(
Stdio $stdio,
EmailParser $parser) {
$this->stdio = $stdio;
$this->parser = $parser;
}
public function process() {
// other code to parse message
// source is set by determining where it came from
$source = 'Etsy';
switch($source) {
case 'Etsy' :
// This bit seems really wrong
$sourceParser = new Etsy\OrderParser();
break;
case 'Amazon' :
$sourceParser = new Amazon\OrderParser();
break;
case 'Ebay' :
$sourceParser = new Ebay\OrderParser();
break;
default :
$sourceParser = null;
}
// Do source specific processing
}
}
我是否需要在确定源后立即拆分我的处理,以便可以使用该源作为参数初始化新的 class?
我在配置中看到的唯一方法是对 return 正确的源 class 执行一个惰性匿名函数,但这也违背了现代设计原则。
我想澄清的是,您不需要像这里的许多 di 容器那样使用 set
方法。可以修改代码为
<?php
namespace Aura\Cli_Project\_Config;
use Aura\Di\Config;
use Aura\Di\Container;
class Common extends Config
{
public function define(Container $di)
{
// commands
$di->params['App\Inventory\Command\IncomingOrder'] = array(
'stdio' => $di->lazyGet('aura/cli-kernel:stdio'),
'parser' => $di->lazyNew('App\Inventory\Utilities\EmailParser')
);
}
// ...
}
当您想将同一个对象传递给许多其他对象时,可以使用 set
。不要使用 newInstance
因为它会在调用时创建对象。您可能需要使用 lazyNew
或 lazyGet
功能。
关于您关于动态决策的问题。这是我的想法,我之前确实遇到过这个问题。但是没有看到我做了什么,所以 iirc 我所做的是向 IncomingOrder
class 注入一个可以创建对象的工厂。这样做的好处是,如果您的源解析需要某种依赖,您可以在工厂内部使用 di。
例如:
<?php
namespace Something;
use Aura\Di\Container;
class SourceFactory
{
public function __construct(Container $di)
{
$this->di = $di;
}
public function newInstance($source)
{
if ($di->has($source)) {
return $di->get($source);
}
// or alternatively create with new as done in switch
}
}
希望对您有所帮助。
谢谢