Skip to content

Commit abfa0c3

Browse files
[DependencyInjection] Fix generating adapters of functional interfaces
1 parent 94c2b34 commit abfa0c3

File tree

8 files changed

+35
-10
lines changed

8 files changed

+35
-10
lines changed

src/Symfony/Component/DependencyInjection/Argument/LazyClosure.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
*/
2626
class LazyClosure
2727
{
28-
public readonly object $service;
28+
public readonly object|string $service;
2929

3030
public function __construct(
3131
private \Closure $initializer,
@@ -87,9 +87,14 @@ public static function getCode(string $initializer, array $callable, Definition
8787
$code = ' implements \\'.$r->name.' { '.$code;
8888
}
8989

90-
$code = 'new class('.$initializer.') extends \\'.self::class
91-
.$code.' { '.($methodReflector->hasReturnType() && 'void' === (string) $methodReflector->getReturnType() ? '' : 'return ').'$this->service->'.$callable[1].'('.$args.'); } '
92-
.'}';
90+
$return = $methodReflector->hasReturnType() && 'void' === (string) $methodReflector->getReturnType() ? '' : 'return ';
91+
92+
if ('__invoke' === $callable[1]) {
93+
$code .= ' { '.$return.'$this->service->'.$callable[1].'('.$args.'); } ';
94+
} else {
95+
$code .= ' { if (\is_object($this->service)) { '.$return.'$this->service->'.$callable[1].'('.$args.'); } else { '.$return.'[$this->service, \''.$callable[1].'\']('.$args.'); } } ';
96+
}
97+
$code = 'new class('.$initializer.') extends \\'.self::class.$code.'}';
9398

9499
return $asClosure ? '('.$code.')->'.$method.'(...)' : $code;
95100
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,8 @@ 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) {

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,10 +1202,10 @@ 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' !== ($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

12111211
return $return.LazyClosure::getCode($initializer, $callable, $definition, $this->container, $id).$tail;

src/Symfony/Component/DependencyInjection/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();

src/Symfony/Component/DependencyInjection/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
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/callable_adapter_consumer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ public function getRemovedIds(): array
5050
*/
5151
protected static function getBarService($container)
5252
{
53-
return $container->services['bar'] = new \Symfony\Component\DependencyInjection\Tests\Dumper\CallableAdapterConsumer(new class(fn () => new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo()) extends \Symfony\Component\DependencyInjection\Argument\LazyClosure implements \Symfony\Component\DependencyInjection\Tests\Compiler\SingleMethodInterface { public function theMethod() { return $this->service->cloneFoo(...\func_get_args()); } });
53+
return $container->services['bar'] = new \Symfony\Component\DependencyInjection\Tests\Dumper\CallableAdapterConsumer(new class(fn () => new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo()) extends \Symfony\Component\DependencyInjection\Argument\LazyClosure implements \Symfony\Component\DependencyInjection\Tests\Compiler\SingleMethodInterface { public function theMethod() { if (\is_object($this->service)) { return $this->service->cloneFoo(...\func_get_args()); } else { return [$this->service, 'cloneFoo'](...\func_get_args()); } } });
5454
}
5555
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/closure_proxy.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,6 @@ protected function createProxy($class, \Closure $factory)
5555
*/
5656
protected static function getClosureProxyService($container, $lazyLoad = true)
5757
{
58-
return $container->services['closure_proxy'] = new class(fn () => ($container->privates['foo'] ??= new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo())) extends \Symfony\Component\DependencyInjection\Argument\LazyClosure implements \Symfony\Component\DependencyInjection\Tests\Compiler\SingleMethodInterface { public function theMethod() { return $this->service->cloneFoo(...\func_get_args()); } };
58+
return $container->services['closure_proxy'] = new class(fn () => ($container->privates['foo'] ??= new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo())) extends \Symfony\Component\DependencyInjection\Argument\LazyClosure implements \Symfony\Component\DependencyInjection\Tests\Compiler\SingleMethodInterface { public function theMethod() { if (\is_object($this->service)) { return $this->service->cloneFoo(...\func_get_args()); } else { return [$this->service, 'cloneFoo'](...\func_get_args()); } } };
5959
}
6060
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/lazy_closure.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ protected function createProxy($class, \Closure $factory)
5757
*/
5858
protected static function getClosure1Service($container, $lazyLoad = true)
5959
{
60-
return $container->services['closure1'] = (new class(fn () => ($container->privates['foo'] ??= new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo())) extends \Symfony\Component\DependencyInjection\Argument\LazyClosure { public function cloneFoo(?\stdClass $bar = null): \Symfony\Component\DependencyInjection\Tests\Compiler\Foo { return $this->service->cloneFoo(...\func_get_args()); } })->cloneFoo(...);
60+
return $container->services['closure1'] = (new class(fn () => ($container->privates['foo'] ??= new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo())) extends \Symfony\Component\DependencyInjection\Argument\LazyClosure { public function cloneFoo(?\stdClass $bar = null): \Symfony\Component\DependencyInjection\Tests\Compiler\Foo { if (\is_object($this->service)) { return $this->service->cloneFoo(...\func_get_args()); } else { return [$this->service, 'cloneFoo'](...\func_get_args()); } } })->cloneFoo(...);
6161
}
6262

6363
/**

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy