Description
It was already proposed few years ago: #12115, but I want to revisit this issue again.
I'm OK if you still don't accept
return function (ContainerConfigurator $c) {
$s = $c->services()
->defaults()
->autoconfigure(true)
->autowire(true)
->private();
$s->set('doctrine_pdo', \Doctrine\DBAL\Connection::class)
->factory(function () {
return DriverManager::getConnection(...);
});
};
, but I want it at least for my projects.
Major issues with this proposal were:
use
may hold reference to object and cannot be inlined to the generated static factory.- it might be actually closed by (to be a closure) some object (
$this
) and unfortunately, PHP documentation makes no difference between anonymous functions and closures. But this one could be solved by requirement to prefix anonymous functions with "static" and throw exception in case of violation:->factory( static function (...) { // ... } )
- this one by @stof, but I still don't get it, probably it was about inlining?
Btw, I see a big drawback with this approach: any time your factory references another of its methods to get a dependency, it will create its own instance of the services, which will not be the same than the shared service used by the container.
- It required to have dependency on
SuperClosure
.
But since you have symfony/contracts
repo, I think we can add something like Symfony\Closures\ClosureDumper
interface and make corresponding changes in the PhpDumper
. It allows you to avoid dependency on 3rd party libraries like SuperClosure
, but opens extension points for users like me:
namespace Symfony\Component\BoostedReflection;
interface AnonymousFunctionDumper
{
/**
* @throws AnonymousFunctionScopeContainsReferences foo () use (&a, $object)
* @throws AnonymousFunctionIsClosureForReal Holds reference to $this
* i.e. is not an anonymous function, strictly speaking
* @return PHP code
*/
public function dump(\Closure $closure): string;
}
btw, Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface
could be moved to the symfony/contracts
too.
So 1.
, 2.
are not problem for me at all; 3.
is weird for me. 4.
not a problem anymore with symfony/contracts
.
Another possible solution is to allow injecting custom container configurators. I can collect all closures, generate static factories for each of them and replace factory definition with it.
Real example: I had a need to integrate Doctrine migrations to the project, but without ORM. I had to translate all these instructions into this Symfony fluent PHP dialect of the plain PHP:
$s->set(Application::class)
->call('setDispatcher', [ref(EventDispatcherInterface::class)])
->call('setHelperSet', [ref(HelperSet::class)])
->call('addCommands', [[
inline(ExecuteCommand::class),
inline(GenerateCommand::class),
inline(LatestCommand::class),
inline(MigrateCommand::class),
inline(DiffCommand::class)->args([ref(MigrationsConfigurator::class)]),
inline(UpToDateCommand::class),
inline(StatusCommand::class),
inline(VersionCommand::class)
]]);
$s->set(Symfony\Component\Console\Helper\HelperSet::class)->args([
[
'db' => inline(ConnectionHelper::class)->args([ref('doctrine_pdo')]),
'question' => inline(QuestionHelper::class),
'configuration' => inline(ConfigurationHelper::class)
->args([
ref('doctrine_pdo'),
inline(Configuration::class)->factory(
[ref(MigrationsConfigurator::class), 'createConfiguration']
)
])
]
]);
instead of copy-pasting:
$s->setApplication::class)
->factory(function (PDO $pdo) {
$cli = new Application();
$cli->setHelperSet(
new \Symfony\Component\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($pdo),
'question' => new \Symfony\Component\Console\Helper\QuestionHelper(),
))
);
$cli->addCommands([
new \Doctrine\DBAL\Migrations\Tools\Console\Command\ExecuteCommand(),
new \Doctrine\DBAL\Migrations\Tools\Console\Command\GenerateCommand(),
new \Doctrine\DBAL\Migrations\Tools\Console\Command\LatestCommand(),
new \Doctrine\DBAL\Migrations\Tools\Console\Command\MigrateCommand(),
new \Doctrine\DBAL\Migrations\Tools\Console\Command\DiffCommand(
// blah blah with $pdo
),
new \Doctrine\DBAL\Migrations\Tools\Console\Command\UpToDateCommand(),
new \Doctrine\DBAL\Migrations\Tools\Console\Command\StatusCommand(),
new \Doctrine\DBAL\Migrations\Tools\Console\Command\VersionCommand()
]);
return $cli;
});
Yes, the last example is awful, but the last one at least is real PHP.
Yes, I could create class with static method, but sometimes you're in position like "argh, I'm lazy for both variants, just, just be cool, OK?".
It is possible to add some extension point for this feature?