Skip to content

Commit a7ec591

Browse files
Merge branch '6.4' into 7.2
* 6.4: [DependencyInjection] Fix generating adapters of functional interfaces
2 parents 5b0974d + c77c3fa commit a7ec591

File tree

6 files changed

+34
-14
lines changed

6 files changed

+34
-14
lines changed

Argument/LazyClosure.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,22 @@ public function __get(mixed $name): mixed
4040
}
4141

4242
if (isset($this->initializer)) {
43-
$this->service = ($this->initializer)();
43+
if (\is_string($service = ($this->initializer)())) {
44+
$service = (new \ReflectionClass($service))->newInstanceWithoutConstructor();
45+
}
46+
$this->service = $service;
4447
unset($this->initializer);
4548
}
4649

4750
return $this->service;
4851
}
4952

50-
public static function getCode(string $initializer, array $callable, Definition $definition, ContainerBuilder $container, ?string $id): string
53+
public static function getCode(string $initializer, array $callable, string $class, ContainerBuilder $container, ?string $id): string
5154
{
5255
$method = $callable[1];
53-
$asClosure = 'Closure' === ($definition->getClass() ?: 'Closure');
5456

55-
if ($asClosure) {
57+
if ($asClosure = 'Closure' === $class) {
5658
$class = ($callable[0] instanceof Reference ? $container->findDefinition($callable[0]) : $callable[0])->getClass();
57-
} else {
58-
$class = $definition->getClass();
5959
}
6060

6161
$r = $container->getReflectionClass($class);

ContainerBuilder.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,14 +1110,15 @@ private function createService(Definition $definition, array &$inlineServices, b
11101110
}
11111111

11121112
if (\is_array($callable) && (
1113-
$callable[0] instanceof Reference
1113+
'Closure' !== $class
1114+
|| $callable[0] instanceof Reference
11141115
|| $callable[0] instanceof Definition && !isset($inlineServices[spl_object_hash($callable[0])])
11151116
)) {
11161117
$initializer = function () use ($callable, &$inlineServices) {
11171118
return $this->doResolveServices($callable[0], $inlineServices);
11181119
};
11191120

1120-
$proxy = eval('return '.LazyClosure::getCode('$initializer', $callable, $definition, $this, $id).';');
1121+
$proxy = eval('return '.LazyClosure::getCode('$initializer', $callable, $class, $this, $id).';');
11211122
$this->shareService($definition, $proxy, $id, $inlineServices);
11221123

11231124
return $proxy;

Dumper/PhpDumper.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,13 +1184,13 @@ private function addNewInstance(Definition $definition, string $return = '', ?st
11841184
throw new RuntimeException(\sprintf('Cannot dump definition because of invalid factory method (%s).', $callable[1] ?: 'n/a'));
11851185
}
11861186

1187-
if (['...'] === $arguments && ($definition->isLazy() || 'Closure' !== ($definition->getClass() ?? 'Closure')) && (
1187+
if (['...'] === $arguments && ('Closure' !== ($class = $definition->getClass() ?: 'Closure') || $definition->isLazy() && (
11881188
$callable[0] instanceof Reference
11891189
|| ($callable[0] instanceof Definition && !$this->definitionVariables->contains($callable[0]))
1190-
)) {
1190+
))) {
11911191
$initializer = 'fn () => '.$this->dumpValue($callable[0]);
11921192

1193-
return $return.LazyClosure::getCode($initializer, $callable, $definition, $this->container, $id).$tail;
1193+
return $return.LazyClosure::getCode($initializer, $callable, $class, $this->container, $id).$tail;
11941194
}
11951195

11961196
if ($callable[0] instanceof Reference

Tests/Argument/LazyClosureTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,23 @@ public function testThrowsWhenNotUsingInterface()
3434
$this->expectException(\RuntimeException::class);
3535
$this->expectExceptionMessage('Cannot create adapter for service "foo" because "Symfony\Component\DependencyInjection\Tests\Argument\LazyClosureTest" is not an interface.');
3636

37-
LazyClosure::getCode('foo', [new \stdClass(), 'bar'], new Definition(LazyClosureTest::class), new ContainerBuilder(), 'foo');
37+
LazyClosure::getCode('foo', [new \stdClass(), 'bar'], LazyClosureTest::class, new ContainerBuilder(), 'foo');
3838
}
3939

4040
public function testThrowsOnNonFunctionalInterface()
4141
{
4242
$this->expectException(\RuntimeException::class);
4343
$this->expectExceptionMessage('Cannot create adapter for service "foo" because interface "Symfony\Component\DependencyInjection\Tests\Argument\NonFunctionalInterface" doesn\'t have exactly one method.');
4444

45-
LazyClosure::getCode('foo', [new \stdClass(), 'bar'], new Definition(NonFunctionalInterface::class), new ContainerBuilder(), 'foo');
45+
LazyClosure::getCode('foo', [new \stdClass(), 'bar'], NonFunctionalInterface::class, new ContainerBuilder(), 'foo');
4646
}
4747

4848
public function testThrowsOnUnknownMethodInInterface()
4949
{
5050
$this->expectException(\RuntimeException::class);
5151
$this->expectExceptionMessage('Cannot create lazy closure for service "bar" because its corresponding callable is invalid.');
5252

53-
LazyClosure::getCode('bar', [new Definition(FunctionalInterface::class), 'bar'], new Definition(\Closure::class), new ContainerBuilder(), 'bar');
53+
LazyClosure::getCode('bar', [new Definition(FunctionalInterface::class), 'bar'], \Closure::class, new ContainerBuilder(), 'bar');
5454
}
5555
}
5656

Tests/ContainerBuilderTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
use Symfony\Component\DependencyInjection\Reference;
4949
use Symfony\Component\DependencyInjection\ServiceLocator;
5050
use Symfony\Component\DependencyInjection\Tests\Compiler\Foo;
51+
use Symfony\Component\DependencyInjection\Tests\Compiler\MyCallable;
5152
use Symfony\Component\DependencyInjection\Tests\Compiler\SingleMethodInterface;
5253
use Symfony\Component\DependencyInjection\Tests\Compiler\Wither;
5354
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
@@ -530,6 +531,19 @@ public function testClosureProxy()
530531
$this->assertInstanceOf(Foo::class, $container->get('closure_proxy')->theMethod());
531532
}
532533

534+
public function testClosureProxyWithStaticMethod()
535+
{
536+
$container = new ContainerBuilder();
537+
$container->register('closure_proxy', SingleMethodInterface::class)
538+
->setPublic('true')
539+
->setFactory(['Closure', 'fromCallable'])
540+
->setArguments([[MyCallable::class, 'theMethodImpl']]);
541+
$container->compile();
542+
543+
$this->assertInstanceOf(SingleMethodInterface::class, $container->get('closure_proxy'));
544+
$this->assertSame(124, $container->get('closure_proxy')->theMethod());
545+
}
546+
533547
public function testCreateServiceClass()
534548
{
535549
$builder = new ContainerBuilder();

Tests/Fixtures/includes/autowiring_classes.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,11 @@ class MyCallable
461461
public function __invoke(): void
462462
{
463463
}
464+
465+
public static function theMethodImpl(): int
466+
{
467+
return 124;
468+
}
464469
}
465470

466471
class MyInlineService

0 commit comments

Comments
 (0)