4

我可以创建一个实例PDO并成功注入它。我PDO::class直接定义并在构造函数中注入了__construct(PDO $pdo). 我需要类似的东西PDO1::classPDO2::class像下面这样注入它:__construct(PDO1 $pdo1, PDO2 $pdo2)但这显然行不通。只有一个PDO类,我需要做的是具有不同数据库凭据的 2 个实例。
最好的方法是什么?

我通过这样的 PDO 设置了一个数据库定义,它可以工作:

文件:dependencies.php

use DI\ContainerBuilder;
use Psr\Container\ContainerInterface;

return function (ContainerBuilder $containerBuilder) {
    $containerBuilder->addDefinitions([
        PDO::class => function (ContainerInterface $c) {
            $dbSettings = $c->get('settings')['db1'];
            $dsn = 'mysql:host=' . $dbSettings['host'] . ';dbname=' . $dbSettings['dbname'];
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            ];
            return new PDO($dsn, $dbSettings['user'], $dbSettings['pass'], $options);
        },
    ]);
};

文件:index.php

...
// Set up dependencies
$dependencies = require __DIR__ . '/../app/dependencies.php';
$dependencies($containerBuilder);
// Build PHP-DI Container instance
$container = $containerBuilder->build();
// Set container to create App with on AppFactory
AppFactory::setContainer($container);
// Instantiate the app
$app = AppFactory::create();
...

文件SomeRepository.php

use PDO;

class SomeRepository{

    protected $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }
}

我在这篇文章中看到过这样的事情:

return function (ContainerBuilder $containerBuilder) {
    $containerBuilder->addDefinitions([
        'db1' => function (ContainerInterface $c) {
            $db1Settings = $c->get('settings')['db1'];
            $dsn = 'mysql:host=' . $db1Settings['host'] . ';dbname=' . $db1Settings['dbname'];
            $options = [ ... ];
            return new PDO($dsn, $db1Settings['user'], $db1Settings['pass'],$options);
        },
        'db2' => function (ContainerInterface $c) {
            $db2Settings = $c->get('settings')['db2'];
            $dsn = 'mysql:host=' . $db2Settings['host'] . ';dbname=' . $db2Settings['dbname'];
            $options = [ ... ];
            return new PDO($dsn, $db2Settings['user'], $db2Settings['pass'],$options);
        },

    ]);
};

但这是最好的方法吗?以及如何在无需注入整个容器的情况下访问存储库类中的连接?

4

2 回答 2

6

您有多种选择:

  1. 扩展 PDO
  2. 自动装配的对象

1. 扩展 PDO

use PDO;

class PDO2 extends PDO
{
    // must be empty
}

容器定义:

use PDO2;

// ...

return [
    PDO::class => function (ContainerInterface $container) {
        return new PDO(...);
    },

    PDO2::class => function (ContainerInterface $container) {
        return new PDO2(...);
    },
];

用法

use PDO;
use PDO2;

class MyRepository
{
    private $pdo;

    private $pdo2;
    
    public function __construct(PDO $pdo, PDO2 $pdo2)
    {
        $this->pdo = $pdo;
        $this->pdo2 = $pdo2;
    }
}

2. 自动装配的对象

请参阅 Matthieu Napoli 的回答:https ://stackoverflow.com/a/57758106/1461181

于 2019-09-03T10:13:07.123 回答
4

如果您的应用程序中有一个类的多个实例(这里您有PDO该类的多个实例),那么您必须配置每次注入哪个实例。

这意味着PDO不能自动装配,因为 PHP-DI 无法根据服务/控制器/等决定您想要哪个实例。

您需要使用配置(请参阅http://php-di.org/doc/php-definitions.html#autowired-objects)来定义为每个服务注入哪个实例(db1db2在您的示例中)。

return [
    MyService::class => DI\autowire()
        ->constructorParameter('pdo', DI\get('db1'))
        ->constructorParameter('pdo2', DI\get('db2')),

    'db1' => function (ContainerInterface $c) {
        return new PDO();
    },
    'db2' => function (ContainerInterface $c) {
        return new PDO();
    },
];
于 2019-09-02T13:49:21.263 回答