Skip to content

[DI] The generated factory code for lazy non-shared services doesn't have access to the $lazyLoad flag #29930

@rado-h

Description

@rado-h

Symfony version(s) affected: 4.2 and 4.1

Description
When a service is declared as non-shared, the generated compiled factory wraps its the initialization in a closure. The problem is that the new function doesn't get access to the $lazyLoad parameter which leads to errors if the generated lazy loading code (for example symfony/proxy-manager-bridge) needs to use it.

How to reproduce

<?php
class MyClass {};

$container = new ContainerBuilder();

$container->register('non_shared_foo', \MyClass::class)->setShared(false)->setLazy(true)->setPublic(true);
$container->compile();

$dumper = new PhpDumper($container);

print_r($dumper->dump(['as_files' => true));

The generated getNonSharedFooService.php looks like this:

<?php

use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;

// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.

$this->factories['non_shared_foo'] = function () {
    // Returns the public 'non_shared_foo' service.

    return new \MyClass();
};

return $this->factories['non_shared_foo']();

This would preclude any implementation of a lazy proxy dumper to check whether the service should be lazy or not. For example if the symfony/proxy-manager-bridge is used:

<?php
$container = new ContainerBuilder();

$container->register('non_shared_foo', \MyClass::class)->setShared(false)->setLazy(true)->setPublic(true);
$container->compile();
$dumper = new PhpDumper($container);
$dumper->setProxyDumper(new \Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper());

print_r($dumper->dump(['as_files' => true]));

the generated getNonSharedFooService.php would look something like this:

<?php

use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;

// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.

$this->factories['non_shared_foo'] = function () {
    // Returns the public 'non_shared_foo' service.

    if ($lazyLoad) {
        return $this->createProxy('MyClass_c5258b3', function () {
            return \MyClass_c5258b3::staticProxyConstructor(function (&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) {
                $wrappedInstance = $this->load('getNonSharedFooService.php', false);

                $proxy->setProxyInitializer(null);

                return true;
            });
        });
    }

    return new \MyClass();
};

return $this->factories['non_shared_foo']();

Possible Solution

add 'use ($lazyLoad) to the generated function signature

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions