Skip to content

Commit c77c3fa

Browse files
[DependencyInjection] Fix generating adapters of functional interfaces
1 parent d089514 commit c77c3fa

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
@@ -1060,14 +1060,15 @@ private function createService(Definition $definition, array &$inlineServices, b
10601060
}
10611061

10621062
if (\is_array($callable) && (
1063-
$callable[0] instanceof Reference
1063+
'Closure' !== $class
1064+
|| $callable[0] instanceof Reference
10641065
|| $callable[0] instanceof Definition && !isset($inlineServices[spl_object_hash($callable[0])])
10651066
)) {
10661067
$initializer = function () use ($callable, &$inlineServices) {
10671068
return $this->doResolveServices($callable[0], $inlineServices);
10681069
};
10691070

1070-
$proxy = eval('return '.LazyClosure::getCode('$initializer', $callable, $definition, $this, $id).';');
1071+
$proxy = eval('return '.LazyClosure::getCode('$initializer', $callable, $class, $this, $id).';');
10711072
$this->shareService($definition, $proxy, $id, $inlineServices);
10721073

10731074
return $proxy;

Dumper/PhpDumper.php

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

1205-
if (['...'] === $arguments && ($definition->isLazy() || 'Closure' !== ($definition->getClass() ?? 'Closure')) && (
1205+
if (['...'] === $arguments && ('Closure' !== ($class = $definition->getClass() ?: 'Closure') || $definition->isLazy() && (
12061206
$callable[0] instanceof Reference
12071207
|| ($callable[0] instanceof Definition && !$this->definitionVariables->contains($callable[0]))
1208-
)) {
1208+
))) {
12091209
$initializer = 'fn () => '.$this->dumpValue($callable[0]);
12101210

1211-
return $return.LazyClosure::getCode($initializer, $callable, $definition, $this->container, $id).$tail;
1211+
return $return.LazyClosure::getCode($initializer, $callable, $class, $this->container, $id).$tail;
12121212
}
12131213

12141214
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
@@ -49,6 +49,7 @@
4949
use Symfony\Component\DependencyInjection\ServiceLocator;
5050
use Symfony\Component\DependencyInjection\Tests\Compiler\Foo;
5151
use Symfony\Component\DependencyInjection\Tests\Compiler\FooAnnotation;
52+
use Symfony\Component\DependencyInjection\Tests\Compiler\MyCallable;
5253
use Symfony\Component\DependencyInjection\Tests\Compiler\SingleMethodInterface;
5354
use Symfony\Component\DependencyInjection\Tests\Compiler\Wither;
5455
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
@@ -522,6 +523,19 @@ public function testClosureProxy()
522523
$this->assertInstanceOf(Foo::class, $container->get('closure_proxy')->theMethod());
523524
}
524525

526+
public function testClosureProxyWithStaticMethod()
527+
{
528+
$container = new ContainerBuilder();
529+
$container->register('closure_proxy', SingleMethodInterface::class)
530+
->setPublic('true')
531+
->setFactory(['Closure', 'fromCallable'])
532+
->setArguments([[MyCallable::class, 'theMethodImpl']]);
533+
$container->compile();
534+
535+
$this->assertInstanceOf(SingleMethodInterface::class, $container->get('closure_proxy'));
536+
$this->assertSame(124, $container->get('closure_proxy')->theMethod());
537+
}
538+
525539
public function testCreateServiceClass()
526540
{
527541
$builder = new ContainerBuilder();

Tests/Fixtures/includes/autowiring_classes.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,4 +582,9 @@ class MyCallable
582582
public function __invoke(): void
583583
{
584584
}
585+
586+
public static function theMethodImpl(): int
587+
{
588+
return 124;
589+
}
585590
}

0 commit comments

Comments
 (0)