I have some PHP-DI dependency definitions in my application which bind to factories producing PDO instances, for example:
$appConfig = [...];
$config1 = $appConfig['mysql'];
$config2 = $appConfig['mssql'];
$builder = new ContainerBuilder();
$containerBuilder->useAttributes(true);
$builder->addDefinitions([
'mysql' => factory(fn(ContainerInterface $c) => new PDO('...', $config1['user'], $config1['pass'])),
'mssql' => factory(fn(ContainerInterface $c) => new PDO('...', $config2['user'], $config2['pass'])),
]);
I want to lazy-load these PDO instances in the classes which use them so that the database connections are only established if the PDOs are used. Consider the following:
class MyClass
{
private PDO $mysql;
private PDO $mssql;
#[Inject(['mysql', 'mssql'])]
public function __construct(PDO $mysql, PDO $mssql)
{
$this->mysql = $mysql;
$this->mssql = $mssql;
}
public function foo()
{
$ps = $this->mysql->prepare('...');
$ps->execute();
return $ps->fetchAll();
}
public function bar()
{
$ps = $this->mssql->prepare('...');
$ps->execute();
return $ps->fetchAll();
}
}
In this scenario, I do not want the dependency container to create the $mysql instance if foo() is never called, and likewise it should not create $mssql if bar() is never called.
Now I could do something like this for each connection:
class MySql
{
private array $config;
private ?PDO $pdo = null;
#[Inject('appconfig')]
public function __construct(array $appConfig)
{
$this->config = $appConfig['mysql'];
}
public function getPdo(): PDO
{
if (is_null($this->pdo))
$this->pdo = new PDO('...', $this->config['user'], $this->config['pass']);
return $this->pdo;
}
}
And then use autowire and lazy for the definition:
$builder->addDefinitions([
'mysql' => autowire(MySql::class)->lazy(),
'mssql' => autowire(MsSql::class)->lazy(),
]);
But this would introduce a lot of boilerplate as each database connection would require it's own class.
Is there a way that I can leverage lazy loading in my factories so I can avoid using autowiring?
NOTE: PHP DI lazy loading works by using proxies to the lazy-loaded objects. I wonder if a potential solution to my scenario would involve returning a proxy from the factory method.