admin管理员组文章数量:1400043
I’m working on a PHP project where I’m using PHP-DI for dependency injection, but I’m struggling to configure a hierarchical structure of classes cleanly and scalably. I have interfaces like ParentLoader
and ChildLoader
, with concrete implementations for different types: XML (e.g., XmlParentLoader
, XmlChildLoader
) that depend on a DOMDocument
, and SQL (e.g., SqlParentLoader
, SqlChildLoader
) that depend on a PDO
. These loaders are hierarchical (ParentLoader
depends on ChildLoader
), and I need to inject them conditionally based on a configuration (e.g., "type" => "xml"
or "type" => "sql"
from a settings file) into a service that uses two ParentLoader
instances.
Here’s a simplified example of my classes:
interface ParentLoader
{
public function load(): array; // Just an example
}
interface ChildLoader
{
public function load(): array; // Just an example
}
class XmlParentLoader implements ParentLoader
{
public function __construct(private XmlChildLoader $childs, private DOMDocument $source)
{
}
public function load(): array
{
// Logic using $source and $childs
return [];
}
}
class XmlChildLoader implements ChildLoader
{
public function __construct(private DOMDocument $source)
{
}
public function load(): array
{
// Logic using $source
return [];
}
}
class SqlParentLoader implements ParentLoader
{
public function __construct(private SqlChildLoader $childs, private PDO $source)
{
}
public function load(): array
{
// Logic using $source and $childs
return [];
}
}
class SqlChildLoader implements ChildLoader
{
public function __construct(private PDO $source)
{
}
public function load(): array
{
// Logic using $source
return [];
}
}
class MyService
{
public function __construct(
private ParentLoader $model, // Based on "model" from settings
private ParentLoader $target // Based on "target" from settings
) {
}
public function execute(): array
{
$dataModel = $this->model->load();
$dataTarget = $this->target->load();
// Combine or process data
return array_merge($dataModel, $dataTarget);
}
}
I’m using PHP-DI to conditionally inject these dependencies based on a configuration. For example, if the config specifies "model" => ["type" => "xml"]
, $model
should use XmlParentLoader
and XmlChildLoader
with a DOMDocument
; if "target" => ["type" => "sql"]
, $target
should use SqlParentLoader
and SqlChildLoader
with a PDO
. Here’s what I tried in my ContainerBuilder
:
use DI\ContainerBuilder;
use Psr\Container\ContainerInterface;
$builder = new ContainerBuilder();
$builder->addDefinitions([
'xml.source' => function () {
$dom = new DOMDocument();
$dom->load('some/path.xml'); // Simplified for example
return $dom;
},
'sql.source' => function () {
return new PDO('mysql:host=localhost;dbname=test', 'user', 'pass'); // Simplified
},
'parent.model' => function (ContainerInterface $container) {
$settings = $container->get('settings'); // Assume settings has "model" and "target"
$type = $settings['model']['type'];
if ($type === 'xml') {
return $container->get('xml.parent.loader.model');
} elseif ($type === 'sql') {
return $container->get('sql.parent.loader.model');
}
throw new \Exception('Invalid type in model configuration');
},
'parent.target' => function (ContainerInterface $container) {
$settings = $container->get('settings');
$type = $settings['target']['type'];
if ($type === 'xml') {
return $container->get('xml.parent.loader.target');
} elseif ($type === 'sql') {
return $container->get('sql.parent.loader.target');
}
throw new \Exception('Invalid type in target configuration');
},
'xml.parent.loader.model' => \DI\create(XmlParentLoader::class)
->constructor(\DI\get('xml.child.loader.model'), \DI\get('xml.source')),
'xml.child.loader.model' => \DI\create(XmlChildLoader::class)
->constructor(\DI\get('xml.source')),
'sql.parent.loader.model' => \DI\create(SqlParentLoader::class)
->constructor(\DI\get('sql.child.loader.model'), \DI\get('sql.source')),
'sql.child.loader.model' => \DI\create(SqlChildLoader::class)
->constructor(\DI\get('sql.source')),
'xml.parent.loader.target' => \DI\create(XmlParentLoader::class)
->constructor(\DI\get('xml.child.loader.target'), \DI\get('xml.source')),
'xml.child.loader.target' => \DI\create(XmlChildLoader::class)
->constructor(\DI\get('xml.source')),
'sql.parent.loader.target' => \DI\create(SqlParentLoader::class)
->constructor(\DI\get('sql.child.loader.target'), \DI\get('sql.source')),
'sql.child.loader.target' => \DI\create(SqlChildLoader::class)
->constructor(\DI\get('sql.source')),
MyService::class => \DI\create()
->constructor(\DI\get('parent.model'), \DI\get('parent.target'));
]);
This works, but it’s a mess. I have to manually define every loader in the hierarchy (e.g., xml.parent.loader.model
, xml.child.loader.model
, etc.) and their dependencies (DOMDocument
or PDO
) for each source (model
and target
). It gets worse when the hierarchy grows (e.g., adding a GrandChildLoader
). My goal is a solution where I don’t need to manually define every loader and its dependencies in the DI container for each source and type combination, making use of autowire for example, which currently I can't because of the "conditional injection". If wasn't for the "source" parameter, I would be able to use autowire, but I need the source.
Is there a better way to structure this with or without PHP-DI? Maybe a factory pattern or some trick to avoid these repetitive definitions? I’d love to leverage autowiring more, but the specific sources (DOMDocument
and PDO
) make it tricky. Any ideas would be awesome!
Thanks!
本文标签: design patternsProblems with complexity in dependency conditional injection with PHPDIStack Overflow
版权声明:本文标题:design patterns - Problems with complexity in dependency conditional injection with PHP-DI - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744165973a2593549.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论