如何将需要变量参数的类放入Dependency Injection容器中?

时间:2017-09-06 21:36:38

标签: php dependency-injection ioc-container zend-servicemanager

当我有一个我需要提供的可变非静态参数时,如何使用Dependency Injection容器?

在我的代码中我想要的是:

$staff = $container->get(Staff::class);

我现在拥有的是:

$staff = new Staff("my_great_username");

请注意,用户名可以更改,并在运行时提供。

我似乎无法将Staff放入我的DI容器中,因为无法在那里指定变量参数。

我的问题是......

我正在使用基于工厂的容器,即Zend\ServiceManager\ServiceManager。这是我用来隐藏实例化细节的工厂:

class StaffFactory
{
    function __invoke(ContainerInterface $container): Staff
    {
        /*
         * I do not seem to know how to get my username here
         * nor if it is the place to do so here
         */
        $staff = new Staff(????????);
        return $staff;
    }
}

我在配置中设置容器的方式是:

'factories' => [
    Staff::class => StaffFactory::class
]

注意:即使参数是"变量",我希望Staff是不可变的。也就是说,一旦它被创建,它就会保持这种状态。因此,我并不特别希望为用户名创建一个setter方法,因为这意味着该类是可变的,而不是。

你有什么建议?

1 个答案:

答案 0 :(得分:2)

我的问题是我有一个变量参数被传递给我的Staff类的构造函数。

解决方案是创建一个StaffCreator类,在其构造函数中没有可变参数,然后编写一个StaffCreator::create方法,该方法接受变量参数。然后,不是将Staff注入到需要Staff的任何类中,而是注入StaffCreator,然后使用它来创建Staff实例。

//Inject this wherever you need Staff
$staffCreator = $container->get(StaffCreator::class);

//use it:
$staff = $this->staffCreator->create("my_great_username");

//code:
class StaffCreatorFactory
{    
    function __invoke(ContainerInterface $container)
    {
        return new StaffCreator();
    }
}

class StaffCreator
{
    function __construct()
    {
        //additional creation parameters possible here
    }

    function create(string $username): Staff
    {
        return new Staff($username);
    }
}

归功于Steve

注意:您可以在上面的代码中创建并添加Interfaces以使DI可重复使用。即StaffCreatorInterfaceStaffInterface。在我的情况下,我保持简单,因为我(还)没有强大的用例来重用接口。