For my PHP-DI definitions I need to make complex calculations beforhand, which are based on other configurations not coming from PHP-DI (those configurations are stored at build time in a variable). As it is harder to explain, than to show, let me give a simplified example which will show, what I would like to do, but will actually not work.
First let’s build the container. The code here is nothing special and shoud work:
<?php
use DIContainer;
use DIContainerBuilder;
class MyContainerBuilder
{
// @param number is the build time (configuration) variable
// I would like to use later
public function build(int $number): Container
{
$builder = new DIContainerBuilder();
$builder->addDefinitions(['number' => $number]);
// In config.php I now want to do some complex calculations
$builder->addDefinitions(__DIR__ . '/config.php');
// here the container may be compiled, such that in production, the complex
// calculations from `config.php` will only be done once (to my understanding)
return $builder->build();
}
}
Now comes the problematic part. The calculation in config.php
<?php
$number = $container->get('number');
// complex calculation:
$number += 1;
return [
'improvedNumber' => $number,
];
This is of course not possible, since the php-di container seems not to be available in the configuration file. Is it still possible to make the value of $number
somehow available in the config.php
?
Sidenote: What I really try to archive is to determine a bunch of services, which shall be injected using php-di. Those services are located in several directories and those directories I must know, when searching for them in the config.php-file.
2
Answers
After a bit more research and still not finding a solution, I decided to do it the ugly way. So the following works for me, but is a bad solution in terms of software design. Basically I decided to use a global variable to transfer my build time variable to the php-di configuration script.
This is a bad solution, since it couples the php-di configuration file with MyContainerBuilder in a rather obscure way and of course this may lead to all Problems one has with Services using static fields/methods. Also one has to keep in mind, that one cannot rely on the code working, when creating multiple containers using
MyContainerBuilder::build
, although the latter is unlikely to happen (Yeah, how could that possibly happen ...).I don’t know if this could help but, you can use a factory to achieve that. The factory can take the container as a parameter and then use it to get the ‘number’ value. Here is an example:
In this example, the ‘improvedNumber’ service is defined as a factory. When you ask the container for ‘improvedNumber’, it will execute the factory function, which will get the ‘number’ from the container, perform the complex calculation, and then return the result.
This way, you can use the value of ‘number’ in your configuration, even though the container is not available in the configuration file. The factory function is only executed when you ask the container for ‘improvedNumber’, so the complex calculation is only performed once, when ‘improvedNumber’ is first requested.