假设我有一组应该由工厂实例化的类。该工厂必须向实例化的类注入一个参数。
<?php
class ClassA
{
public function __constructor(
\My\Logger $logger,
\Dependency\For\ClassA $dependencyA2,
\One\More\Dependency\For\ClassA $dependencyA3,
...
string $parameterInjectedByTheFactory
) {
$this->logger = $logger;
$this->dependencyA2 = $dependencyA2;
...
$this->parameterInjectedByTheFactory = $parameterInjectedByTheFactory;
}
}
和
<?php
class ClassB
{
public function __constructor(
\My\Logger $logger,
\Dependency\For\ClassB $dependencyB2,
\One\More\Dependency\For\ClassB $dependencyB3,
...
string $parameterInjectedByTheFactory
) {
$this->logger = $logger;
$this->dependencyB2 = $dependencyB2;
...
$this->parameterInjectedByTheFactory = $parameterInjectedByTheFactory;
}
}
我觉得下面的课是错的。它不应该知道ClassA
和ClassB
的特定依赖关系,不是吗?
class Factory
{
public function __constructor(
\My\Logger $logger
) {
$this->logger = $logger;
}
public function make($class, $myParameter)
{
switch($class)
{
case 'ClassA':
return new $class(
$this->logger,
new \Dependency\For\ClassA,
...
$myParameter
)
case 'ClassB':
return new $class(
$this->logger,
new \Dependency\For\ClassB,
...
$myParameter
)
}
}
}
我想利用DI自动装配来实例化classA和classB,但在工厂中注入容器是一种不好的做法。
一个更现实的例子。我有一个EndpointManager
方法get($endpointCode)
,它在数组中查找$ endpointCode。此数组条目具有构建端点的信息:
<?php
[
'endpoint1' => [
'class' => '\My\Class\For\Dealing\With\MySQL',
'connectionData' => 'mysql:user@localhost',
],
'endpoint2' => [
'class' => '\My\Class\For\Dealing\With\REST',
'connectionData' => [
'url': 'https://localhost/api/rest/',
...
],
],
]
EndpointManager
必须实例化'class'
条目中定义的类的对象,并将connectionData
传递给它。但\My\Class\For\Dealing\With\MySQL
和\My\Class\For\Dealing\With\REST
的构造函数是异构的,每个构造函数都有自己可能存在的大量依赖关系。有没有办法利用DI来实例化这些对象。
这种情况的最佳方法是什么?
答案 0 :(得分:0)
您可以将具体类的创建委托给匿名函数,例如
<?php
$dependencyManager>add('endpoint1', function ($di) {
return new \My\Class\For\Dealing\With\MySQL('mysql:user@localhost', .., ...);
});
$dependencyManager>add('endpoint2', function ($di) {
return new \My\Class\For\Dealing\With\REST('https://localhost/api/rest/', .., ..., ...);
});
获取实例类:
<?php
$endpoint1Instance = $dependencyManager->get('endpoint1');
$endpoint2Instance = $dependencyManager->get('endpoint2');
其中add()
和get()
方法可以声明如下:
<?php
class DependencyManager
{
private $dependencies = [];
...
public function add($key, callable $factory)
{
$this->dependencies[$key]['instance'] = null;
$this->dependencies[$key]['factory'] = $factory;
}
public function get($key)
{
if (isset($this->dependencies[$key]) {
$instance = $this->dependencies[$key]['instance'];
if (is_null($instance)) {
$instance = $this->dependencies[$key]['factory']($this);
$this->dependencies[$key]['instance'] = $instance;
}
return $instance;
} else {
throw new Exception('not found');
}
}
...
}
您可能希望查看现有的依赖关系管理器实现,例如Pimple。