[Di] Remove closure-proxy arguments

This commit is contained in:
Nicolas Grekas 2017-06-01 22:30:09 +02:00
parent 3fc1189910
commit 57daadbf67
41 changed files with 30 additions and 733 deletions

View File

@ -127,7 +127,7 @@ EventDispatcher
---------------
* The `ContainerAwareEventDispatcher` class has been deprecated.
Use `EventDispatcher` with closure-proxy injection instead.
Use `EventDispatcher` with closure factories instead.
Finder
------

View File

@ -132,7 +132,7 @@ EventDispatcher
---------------
* The `ContainerAwareEventDispatcher` class has been removed.
Use `EventDispatcher` with closure-proxy injection instead.
Use `EventDispatcher` with closure factories instead.
ExpressionLanguage
------------------

View File

@ -312,10 +312,6 @@ abstract class Descriptor implements DescriptorInterface
{
$r = new \ReflectionFunction($closure);
if (preg_match('#^/\*\* @closure-proxy ([^: ]++)::([^: ]++) \*/$#', $r->getDocComment(), $m)) {
return sprintf('%s::%s', $m[1], $m[2]);
}
return 'closure';
}
}

View File

@ -14,7 +14,6 @@ namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@ -343,9 +342,6 @@ class TextDescriptor extends Descriptor
$argumentsInformation[] = sprintf('Service(%s)', (string) $argument);
} elseif ($argument instanceof IteratorArgument) {
$argumentsInformation[] = sprintf('Iterator (%d element(s))', count($argument->getValues()));
} elseif ($argument instanceof ClosureProxyArgument) {
list($reference, $method) = $argument->getValues();
$argumentsInformation[] = sprintf('ClosureProxy(Service(%s)::%s())', $reference, $method);
} elseif ($argument instanceof Definition) {
$argumentsInformation[] = 'Inlined Service';
} else {

View File

@ -12,7 +12,6 @@
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@ -444,11 +443,6 @@ class XmlDescriptor extends Descriptor
foreach ($this->getArgumentNodes($argument->getValues(), $dom) as $childArgumentXML) {
$argumentXML->appendChild($childArgumentXML);
}
} elseif ($argument instanceof ClosureProxyArgument) {
list($reference, $method) = $argument->getValues();
$argumentXML->setAttribute('type', 'closure-proxy');
$argumentXML->setAttribute('id', (string) $reference);
$argumentXML->setAttribute('method', $method);
} elseif ($argument instanceof Definition) {
$argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true)->childNodes->item(0), true));
} elseif (is_array($argument)) {

View File

@ -12,7 +12,6 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
@ -119,7 +118,6 @@ class ObjectsProvider
new Reference('definition_1'),
new Reference('definition_2'),
)))
->addArgument(new ClosureProxyArgument('definition1', 'get'))
->setFactory(array('Full\\Qualified\\FactoryClass', 'get')),
'definition_2' => $definition2
->setPublic(false)

View File

@ -60,13 +60,6 @@
"type": "service",
"id": "definition_2"
}
],
[
{
"type": "service",
"id": "definition1"
},
"get"
]
],
"file": null,

View File

@ -22,7 +22,6 @@
<argument type="service" id="definition_1"/>
<argument type="service" id="definition_2"/>
</argument>
<argument type="closure-proxy" id="definition1" method="get"/>
</definition>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerBuilder"/>
</container>

View File

@ -58,13 +58,6 @@
"type": "service",
"id": "definition_2"
}
],
[
{
"type": "service",
"id": "definition1"
},
"get"
]
],
"file": null,

View File

@ -1,23 +1,22 @@
---------------- -------------------------------------------
 Option   Value 
---------------- -------------------------------------------
Service ID -
Class Full\Qualified\Class1
Tags -
Public yes
Synthetic no
Lazy yes
Shared yes
Abstract yes
Autowired no
Autoconfigured no
Factory Class Full\Qualified\FactoryClass
Factory Method get
 Arguments Service(definition2) 
 %parameter% 
 Inlined Service 
 Array (3 element(s)) 
 Iterator (2 element(s)) 
 ClosureProxy(Service(definition1)::get())
---------------- -------------------------------------------
---------------- -----------------------------
 Option   Value 
---------------- -----------------------------
Service ID -
Class Full\Qualified\Class1
Tags -
Public yes
Synthetic no
Lazy yes
Shared yes
Abstract yes
Autowired no
Autoconfigured no
Factory Class Full\Qualified\FactoryClass
Factory Method get
 Arguments Service(definition2) 
 %parameter% 
 Inlined Service 
 Array (3 element(s)) 
 Iterator (2 element(s))
---------------- -----------------------------

View File

@ -20,5 +20,4 @@
<argument type="service" id="definition_1"/>
<argument type="service" id="definition_2"/>
</argument>
<argument type="closure-proxy" id="definition1" method="get"/>
</definition>

View File

@ -1,50 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\DependencyInjection\Argument;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class ClosureProxyArgument implements ArgumentInterface
{
private $reference;
private $method;
public function __construct($id, $method, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
{
$this->reference = new Reference($id, $invalidBehavior);
$this->method = $method;
}
/**
* {@inheritdoc}
*/
public function getValues()
{
return array($this->reference, $this->method);
}
/**
* {@inheritdoc}
*/
public function setValues(array $values)
{
if (!$values[0] instanceof Reference) {
throw new InvalidArgumentException(sprintf('A ClosureProxyArgument must hold a Reference, "%s" given.', is_object($values[0]) ? get_class($values[0]) : gettype($values[0])));
}
list($this->reference, $this->method) = $values;
}
}

View File

@ -20,7 +20,6 @@ CHANGELOG
* added support for omitting the factory class name in a service definition if the definition class is set
* deprecated case insensitivity of service identifiers
* added "iterator" argument type for lazy iteration over a set of values and services
* added "closure-proxy" argument type for turning services' methods into lazy callables
* added file-wide configurable defaults for service attributes "public", "tags",
"autowire" and "autoconfigure"
* made the "class" attribute optional, using the "id" as fallback

View File

@ -12,7 +12,6 @@
namespace Symfony\Component\DependencyInjection;
use Psr\Container\ContainerInterface as PsrContainerInterface;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
@ -1161,31 +1160,6 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
return $count;
});
} elseif ($value instanceof ClosureProxyArgument) {
$parameterBag = $this->getParameterBag();
list($reference, $method) = $value->getValues();
if ('service_container' === $id = (string) $reference) {
$class = parent::class;
} elseif (!$this->hasDefinition($id) && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
return;
} else {
$class = $parameterBag->resolveValue($this->findDefinition($id)->getClass());
}
if (!method_exists($class, $method = $parameterBag->resolveValue($method))) {
throw new InvalidArgumentException(sprintf('Cannot create closure-proxy for service "%s": method "%s::%s" does not exist.', $id, $class, $method));
}
$r = new \ReflectionMethod($class, $method);
if (!$r->isPublic()) {
throw new RuntimeException(sprintf('Cannot create closure-proxy for service "%s": method "%s::%s" must be public.', $id, $class, $method));
}
foreach ($r->getParameters() as $p) {
if ($p->isPassedByReference()) {
throw new RuntimeException(sprintf('Cannot create closure-proxy for service "%s": parameter "$%s" of method "%s::%s" must not be passed by reference.', $id, $p->name, $class, $method));
}
}
$value = function () use ($id, $method) {
return call_user_func_array(array($this->get($id), $method), func_get_args());
};
} elseif ($value instanceof Reference) {
$value = $this->get((string) $value, $value->getInvalidBehavior());
} elseif ($value instanceof Definition) {

View File

@ -12,7 +12,6 @@
namespace Symfony\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Variable;
@ -27,7 +26,6 @@ use Symfony\Component\DependencyInjection\Exception\EnvParameterException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
use Symfony\Component\DependencyInjection\ExpressionLanguage;
@ -67,7 +65,6 @@ class PhpDumper extends Dumper
private $docStar;
private $serviceIdToMethodNameMap;
private $usedMethodNames;
private $baseClass;
/**
* @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
@ -125,7 +122,6 @@ class PhpDumper extends Dumper
$this->classResources = array();
$this->initializeMethodNamesMap($options['base_class']);
$this->baseClass = $options['base_class'];
$this->docStar = $options['debug'] ? '*' : '';
@ -1465,34 +1461,6 @@ EOF;
return implode("\n", $code);
}
if ($value instanceof ClosureProxyArgument) {
list($reference, $method) = $value->getValues();
$method = substr($this->dumpLiteralClass($this->dumpValue($method)), 1);
if ('service_container' === (string) $reference) {
$class = $this->baseClass;
} elseif (!$this->container->hasDefinition((string) $reference) && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
return 'null';
} else {
$class = substr($this->dumpLiteralClass($this->dumpValue($this->container->findDefinition((string) $reference)->getClass())), 1);
}
if (false !== strpos($class, '$') || false !== strpos($method, '$')) {
throw new RuntimeException(sprintf('Cannot dump definition for service "%s": dynamic class names or methods, and closure-proxies are incompatible with each other.', $reference));
}
if (!method_exists($class, $method)) {
throw new InvalidArgumentException(sprintf('Cannot create closure-proxy for service "%s": method "%s::%s" does not exist.', $reference, $class, $method));
}
$r = $this->container->getReflectionClass($class)->getMethod($method);
if (!$r->isPublic()) {
throw new InvalidArgumentException(sprintf('Cannot create closure-proxy for service "%s": method "%s::%s" must be public.', $reference, $class, $method));
}
$signature = preg_replace('/^(&?)[^(]*/', '$1', ProxyHelper::getSignature($r, $call));
$return = 'void' !== ProxyHelper::getTypeHint($r);
return sprintf("/** @closure-proxy %s::%s */ function %s {\n %s%s->%s;\n }", $class, $method, $signature, $return ? 'return ' : '', $this->dumpValue($reference), $call);
}
} finally {
list($this->definitionVariables, $this->referenceVariables, $this->variableCount) = $scope;
}

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -302,11 +301,6 @@ class XmlDumper extends Dumper
} elseif ($value instanceof IteratorArgument) {
$element->setAttribute('type', 'iterator');
$this->convertParameters($value->getValues(), $type, $element, 'key');
} elseif ($value instanceof ClosureProxyArgument) {
list($reference, $method) = $value->getValues();
$element->setAttribute('type', 'closure-proxy');
$element->setAttribute('id', (string) $reference);
$element->setAttribute('method', $method);
} elseif ($value instanceof Reference) {
$element->setAttribute('type', 'service');
$element->setAttribute('id', (string) $value);

View File

@ -15,7 +15,6 @@ use Symfony\Component\Yaml\Dumper as YmlDumper;
use Symfony\Component\Yaml\Tag\TaggedValue;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -256,8 +255,6 @@ class YamlDumper extends Dumper
if ($value instanceof ArgumentInterface) {
if ($value instanceof IteratorArgument) {
$tag = 'iterator';
} elseif ($value instanceof ClosureProxyArgument) {
$tag = 'closure_proxy';
} else {
throw new RuntimeException(sprintf('Unspecified Yaml tag for type "%s".', get_class($value)));
}

View File

@ -18,54 +18,6 @@ namespace Symfony\Component\DependencyInjection\LazyProxy;
*/
class ProxyHelper
{
/**
* @return string The signature of the passed function, return type and function/method name included if any
*/
public static function getSignature(\ReflectionFunctionAbstract $r, &$call = null)
{
$signature = array();
$call = array();
foreach ($r->getParameters() as $i => $p) {
$k = '$'.$p->name;
if (method_exists($p, 'isVariadic') && $p->isVariadic()) {
$k = '...'.$k;
}
$call[] = $k;
if ($p->isPassedByReference()) {
$k = '&'.$k;
}
if ($type = self::getTypeHint($r, $p)) {
$k = $type.' '.$k;
}
if ($type && $p->allowsNull()) {
$k = '?'.$k;
}
try {
$k .= ' = '.self::export($p->getDefaultValue());
if ($type && $p->allowsNull() && null === $p->getDefaultValue()) {
$k = substr($k, 1);
}
} catch (\ReflectionException $e) {
if ($type && $p->allowsNull() && !class_exists('ReflectionNamedType', false)) {
$k .= ' = null';
$k = substr($k, 1);
}
}
$signature[] = $k;
}
$call = ($r->isClosure() ? '' : $r->name).'('.implode(', ', $call).')';
if ($type = self::getTypeHint($r)) {
$type = ': '.($r->getReturnType()->allowsNull() ? '?' : '').$type;
}
return ($r->returnsReference() ? '&' : '').($r->isClosure() ? '' : $r->name).'('.implode(', ', $signature).')'.$type;
}
/**
* @return string|null The FQCN or builtin name of the type hint, or null when the type hint references an invalid self|parent context
*/

View File

@ -14,7 +14,6 @@ namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ChildDefinition;
@ -493,15 +492,6 @@ class XmlFileLoader extends FileLoader
case 'expression':
$arguments[$key] = new Expression($arg->nodeValue);
break;
case 'closure-proxy':
if (!$arg->getAttribute('id')) {
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="closure-proxy" has no or empty "id" attribute in "%s".', $name, $file));
}
if (!$arg->getAttribute('method')) {
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="closure-proxy" has no or empty "method" attribute in "%s".', $name, $file));
}
$arguments[$key] = new ClosureProxyArgument($arg->getAttribute('id'), $arg->getAttribute('method'), $invalidBehavior);
break;
case 'collection':
$arguments[$key] = $this->getArgumentsAsPhp($arg, $name, $file, false);
break;

View File

@ -13,7 +13,6 @@ namespace Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -679,21 +678,6 @@ class YamlFileLoader extends FileLoader
throw new InvalidArgumentException(sprintf('"!iterator" tag only accepts arrays of "@service" references in "%s".', $file));
}
}
if ('closure_proxy' === $value->getTag()) {
if (!is_array($argument) || array(0, 1) !== array_keys($argument) || !is_string($argument[0]) || !is_string($argument[1]) || 0 !== strpos($argument[0], '@') || 0 === strpos($argument[0], '@@')) {
throw new InvalidArgumentException(sprintf('"!closure_proxy" tagged values must be arrays of [@service, method] in "%s".', $file));
}
if (0 === strpos($argument[0], '@?')) {
$argument[0] = substr($argument[0], 2);
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
} else {
$argument[0] = substr($argument[0], 1);
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
}
return new ClosureProxyArgument($argument[0], $argument[1], $invalidBehavior);
}
if ('service' === $value->getTag()) {
if ($isParameter) {
throw new InvalidArgumentException(sprintf('Using an anonymous service in a parameter is not allowed in "%s".', $file));

View File

@ -218,7 +218,6 @@
<xsd:attribute name="index" type="xsd:integer" />
<xsd:attribute name="on-invalid" type="invalid_sequence" />
<xsd:attribute name="strict" type="boolean" />
<xsd:attribute name="method" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="call">
@ -244,7 +243,6 @@
<xsd:enumeration value="string" />
<xsd:enumeration value="constant" />
<xsd:enumeration value="iterator" />
<xsd:enumeration value="closure-proxy" />
</xsd:restriction>
</xsd:simpleType>

View File

@ -18,7 +18,7 @@ use Symfony\Component\DependencyInjection\Compiler\RepeatedPass;
use Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
class InlineServiceDefinitionsPassTest extends TestCase
@ -233,8 +233,8 @@ class InlineServiceDefinitionsPassTest extends TestCase
->setShared(false)
;
$container
->register('closure-proxy')
->setArguments(array(new ClosureProxyArgument('inline', 'method')))
->register('service-closure')
->setArguments(array(new ServiceClosureArgument(new Reference('inline'))))
;
$container
->register('iterator')
@ -243,7 +243,7 @@ class InlineServiceDefinitionsPassTest extends TestCase
$this->process($container);
$values = $container->getDefinition('closure-proxy')->getArgument(0)->getValues();
$values = $container->getDefinition('service-closure')->getArgument(0)->getValues();
$this->assertInstanceOf(Reference::class, $values[0]);
$this->assertSame('inline', (string) $values[0]);

View File

@ -20,7 +20,6 @@ use Symfony\Component\Config\Resource\ComposerResource;
use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\Config\Resource\DirectoryResource;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
@ -1008,63 +1007,6 @@ class ContainerBuilderTest extends TestCase
$this->assertEquals(A::class, (string) $container->getDefinition('b')->getArgument(0));
}
public function testClosureProxy()
{
$container = new ContainerBuilder();
$container->register('foo', 'stdClass')
->setProperty('foo', new ClosureProxyArgument('bar', 'c'))
;
$container->register('bar', A::class);
$foo = $container->get('foo');
$this->assertInstanceOf('Closure', $foo->foo);
$this->assertSame(123, call_user_func($foo->foo));
}
public function testClosureProxyContainer()
{
$container = new ContainerBuilder();
$container->register('foo', 'stdClass')
->setProperty('foo', new ClosureProxyArgument('service_container', 'get'))
;
$foo = $container->get('foo');
$this->assertInstanceOf('Closure', $foo->foo);
$this->assertSame($foo, call_user_func($foo->foo, 'foo'));
}
public function testClosureProxyOnInvalidNull()
{
$container = new ContainerBuilder();
$container->register('foo', 'stdClass')
->setProperty('foo', new ClosureProxyArgument('bar', 'c', ContainerInterface::NULL_ON_INVALID_REFERENCE))
;
$foo = $container->get('foo');
$this->assertNull($foo->foo);
}
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
* @expectedExceptionMessage You have requested a non-existent service "bar".
*/
public function testClosureProxyOnInvalidException()
{
$container = new ContainerBuilder();
$container->register('foo', 'stdClass')
->setProperty('foo', new ClosureProxyArgument('bar', 'c'))
;
$container->get('foo');
}
public function testClassFromId()
{
$container = new ContainerBuilder();
@ -1148,10 +1090,6 @@ class FooClass
class A
{
public function c()
{
return 123;
}
}
class B

View File

@ -472,46 +472,6 @@ class PhpDumperTest extends TestCase
$this->assertEmpty(iterator_to_array($lazyContext->lazyEmptyValues));
}
public function testClosureProxy()
{
$container = include self::$fixturesPath.'/containers/container31.php';
$container->compile();
$dumper = new PhpDumper($container);
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services31.php', $dumper->dump());
$res = $container->getResources();
$this->assertSame('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Container31\Foo', (string) array_pop($res));
}
/**
* @requires PHP 7.1
*/
public function testClosureProxyWithVoidReturnType()
{
$container = include self::$fixturesPath.'/containers/container_dump_proxy_with_void_return_type.php';
$container->compile();
$dumper = new PhpDumper($container);
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_dump_proxy_with_void_return_type.php', $dumper->dump());
$res = $container->getResources();
$this->assertSame('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\ContainerVoid\Foo', (string) array_pop($res));
}
/**
* @requires PHP 7.1
*/
public function testClosureProxyPhp71()
{
$container = include self::$fixturesPath.'/containers/container32.php';
$container->compile();
$dumper = new PhpDumper($container);
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services32.php', $dumper->dump());
$res = $container->getResources();
$this->assertSame('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Container32\Foo', (string) array_pop($res));
}
public function testNormalizedId()
{
$container = include self::$fixturesPath.'/containers/container33.php';

View File

@ -1,37 +0,0 @@
<?php
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Container31;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
if (!class_exists(Foo::class, false)) {
class Foo
{
public function withNoArgs()
{
}
public function withArgs(parent $a, self $b = null, $c = array(123))
{
}
public function &withRefs(&$a = null, &$b)
{
}
}
}
$container = new ContainerBuilder();
$container->register('foo', Foo::class);
$container->register('bar', 'stdClass')
->setProperty('foo', array(
new ClosureProxyArgument('foo', 'withNoArgs'),
new ClosureProxyArgument('foo', 'withArgs'),
new ClosureProxyArgument('foo', 'withRefs'),
))
;
return $container;

View File

@ -1,37 +0,0 @@
<?php
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Container32;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
if (!class_exists(Foo::class, false)) {
class Foo
{
public function withVariadic($a, &...$c)
{
}
public function withNullable(?int $a)
{
}
public function withReturnType(): \Bar
{
}
}
}
$container = new ContainerBuilder();
$container->register('foo', Foo::class);
$container->register('bar', 'stdClass')
->setProperty('foo', array(
new ClosureProxyArgument('foo', 'withVariadic'),
new ClosureProxyArgument('foo', 'withNullable'),
new ClosureProxyArgument('foo', 'withReturnType'),
))
;
return $container;

View File

@ -2,7 +2,6 @@
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Container33;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
if (!class_exists(Foo::class, false)) {

View File

@ -3,7 +3,6 @@
require_once __DIR__.'/../includes/classes.php';
require_once __DIR__.'/../includes/foo.php';
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
@ -140,9 +139,5 @@ $container
->register('lazy_context_ignore_invalid_ref', 'LazyContext')
->setArguments(array(new IteratorArgument(array(new Reference('foo.baz'), new Reference('invalid', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))), new IteratorArgument(array())))
;
$container
->register('closure_proxy', 'BarClass')
->setArguments(array(new ClosureProxyArgument('closure_proxy', 'getBaz')))
;
return $container;

View File

@ -1,27 +0,0 @@
<?php
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\ContainerVoid;
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
if (!class_exists(Foo::class, false)) {
class Foo
{
public function withVoid(): void
{
}
}
}
$container = new ContainerBuilder();
$container->register('foo', Foo::class);
$container->register('bar', 'stdClass')
->setProperty('foo', array(
new ClosureProxyArgument('foo', 'withVoid'),
))
;
return $container;

View File

@ -29,7 +29,6 @@ digraph sc {
node_factory_service_simple [label="factory_service_simple\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_lazy_context [label="lazy_context\nLazyContext\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_lazy_context_ignore_invalid_ref [label="lazy_context_ignore_invalid_ref\nLazyContext\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_closure_proxy [label="closure_proxy\nBarClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"];
node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"];
node_foobaz [label="foobaz\n\n", shape=record, fillcolor="#ff9999", style="filled"];
@ -51,5 +50,4 @@ digraph sc {
node_lazy_context -> node_service_container [label="" style="filled" color="#9999ff"];
node_lazy_context_ignore_invalid_ref -> node_foo_baz [label="" style="filled" color="#9999ff"];
node_lazy_context_ignore_invalid_ref -> node_invalid [label="" style="filled" color="#9999ff"];
node_closure_proxy -> node_closure_proxy [label="" style="filled" color="#9999ff"];
}

View File

@ -61,29 +61,6 @@ class ProjectServiceContainer extends Container
return true;
}
/**
* Gets the 'bar' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \stdClass A stdClass instance
*/
protected function getBarService()
{
$this->services['bar'] = $instance = new \stdClass();
$instance->foo = array(0 => /** @closure-proxy Symfony\Component\DependencyInjection\Tests\Fixtures\Container31\Foo::withNoArgs */ function () {
return ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->get('foo')) && false ?: '_'}->withNoArgs();
}, 1 => /** @closure-proxy Symfony\Component\DependencyInjection\Tests\Fixtures\Container31\Foo::withArgs */ function ($a, \Symfony\Component\DependencyInjection\Tests\Fixtures\Container31\Foo $b = NULL, $c = array(0 => 123)) {
return ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->get('foo')) && false ?: '_'}->withArgs($a, $b, $c);
}, 2 => /** @closure-proxy Symfony\Component\DependencyInjection\Tests\Fixtures\Container31\Foo::withRefs */ function &(&$a = NULL, &$b) {
return ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->get('foo')) && false ?: '_'}->withRefs($a, $b);
});
return $instance;
}
/**
* Gets the 'foo' service.
*

View File

@ -1,99 +0,0 @@
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/**
* ProjectServiceContainer.
*
* This class has been auto-generated
* by the Symfony Dependency Injection Component.
*
* @final since Symfony 3.3
*/
class ProjectServiceContainer extends Container
{
private $parameters;
private $targetDirs = array();
/**
* Constructor.
*/
public function __construct()
{
$this->services = array();
$this->methodMap = array(
'bar' => 'getBarService',
'foo' => 'getFooService',
);
$this->aliases = array();
}
/**
* {@inheritdoc}
*/
public function compile()
{
throw new LogicException('You cannot compile a dumped container that was already compiled.');
}
/**
* {@inheritdoc}
*/
public function isCompiled()
{
return true;
}
/**
* {@inheritdoc}
*/
public function isFrozen()
{
@trigger_error(sprintf('The %s() method is deprecated since version 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED);
return true;
}
/**
* Gets the 'bar' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \stdClass A stdClass instance
*/
protected function getBarService()
{
$this->services['bar'] = $instance = new \stdClass();
$instance->foo = array(0 => /** @closure-proxy Symfony\Component\DependencyInjection\Tests\Fixtures\Container32\Foo::withVariadic */ function ($a, &...$c) {
return ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->get('foo')) && false ?: '_'}->withVariadic($a, ...$c);
}, 1 => /** @closure-proxy Symfony\Component\DependencyInjection\Tests\Fixtures\Container32\Foo::withNullable */ function (?int $a) {
return ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->get('foo')) && false ?: '_'}->withNullable($a);
}, 2 => /** @closure-proxy Symfony\Component\DependencyInjection\Tests\Fixtures\Container32\Foo::withReturnType */ function (): \Bar {
return ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->get('foo')) && false ?: '_'}->withReturnType();
});
return $instance;
}
/**
* Gets the 'foo' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \Symfony\Component\DependencyInjection\Tests\Fixtures\Container32\Foo A Symfony\Component\DependencyInjection\Tests\Fixtures\Container32\Foo instance
*/
protected function getFooService()
{
return $this->services['foo'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\Container32\Foo();
}
}

View File

@ -34,7 +34,6 @@ class ProjectServiceContainer extends Container
$this->methodMap = array(
'bar' => 'getBarService',
'baz' => 'getBazService',
'closure_proxy' => 'getClosureProxyService',
'configurator_service' => 'getConfiguratorServiceService',
'configurator_service_simple' => 'getConfiguratorServiceSimpleService',
'configured_service' => 'getConfiguredServiceService',
@ -109,21 +108,6 @@ class ProjectServiceContainer extends Container
return $instance;
}
/**
* Gets the 'closure_proxy' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \BarClass A BarClass instance
*/
protected function getClosureProxyService()
{
return $this->services['closure_proxy'] = new \BarClass(/** @closure-proxy BarClass::getBaz */ function () {
return ${($_ = isset($this->services['closure_proxy']) ? $this->services['closure_proxy'] : $this->get('closure_proxy')) && false ?: '_'}->getBaz();
});
}
/**
* Gets the 'configured_service' service.
*

View File

@ -32,7 +32,6 @@ class ProjectServiceContainer extends Container
$this->methodMap = array(
'bar' => 'getBarService',
'baz' => 'getBazService',
'closure_proxy' => 'getClosureProxyService',
'configured_service' => 'getConfiguredServiceService',
'configured_service_simple' => 'getConfiguredServiceSimpleService',
'decorator_service' => 'getDecoratorServiceService',
@ -119,21 +118,6 @@ class ProjectServiceContainer extends Container
return $instance;
}
/**
* Gets the 'closure_proxy' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \BarClass A BarClass instance
*/
protected function getClosureProxyService()
{
return $this->services['closure_proxy'] = new \BarClass(/** @closure-proxy BarClass::getBaz */ function () {
return ${($_ = isset($this->services['closure_proxy']) ? $this->services['closure_proxy'] : $this->get('closure_proxy')) && false ?: '_'}->getBaz();
});
}
/**
* Gets the 'configured_service' service.
*

View File

@ -1,95 +0,0 @@
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/**
* ProjectServiceContainer.
*
* This class has been auto-generated
* by the Symfony Dependency Injection Component.
*
* @final since Symfony 3.3
*/
class ProjectServiceContainer extends Container
{
private $parameters;
private $targetDirs = array();
/**
* Constructor.
*/
public function __construct()
{
$this->services = array();
$this->methodMap = array(
'bar' => 'getBarService',
'foo' => 'getFooService',
);
$this->aliases = array();
}
/**
* {@inheritdoc}
*/
public function compile()
{
throw new LogicException('You cannot compile a dumped container that was already compiled.');
}
/**
* {@inheritdoc}
*/
public function isCompiled()
{
return true;
}
/**
* {@inheritdoc}
*/
public function isFrozen()
{
@trigger_error(sprintf('The %s() method is deprecated since version 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED);
return true;
}
/**
* Gets the 'bar' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \stdClass A stdClass instance
*/
protected function getBarService()
{
$this->services['bar'] = $instance = new \stdClass();
$instance->foo = array(0 => /** @closure-proxy Symfony\Component\DependencyInjection\Tests\Fixtures\ContainerVoid\Foo::withVoid */ function (): void {
${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->get('foo')) && false ?: '_'}->withVoid();
});
return $instance;
}
/**
* Gets the 'foo' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \Symfony\Component\DependencyInjection\Tests\Fixtures\ContainerVoid\Foo A Symfony\Component\DependencyInjection\Tests\Fixtures\ContainerVoid\Foo instance
*/
protected function getFooService()
{
return $this->services['foo'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\ContainerVoid\Foo();
}
}

View File

@ -130,9 +130,6 @@
</argument>
<argument type="iterator"/>
</service>
<service id="closure_proxy" class="BarClass">
<argument type="closure-proxy" id="closure_proxy" method="getBaz"/>
</service>
<service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/>
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>
<service id="alias_for_foo" alias="foo"/>

View File

@ -116,9 +116,6 @@ services:
lazy_context_ignore_invalid_ref:
class: LazyContext
arguments: [!iterator ['@foo.baz', '@?invalid'], !iterator []]
closure_proxy:
class: BarClass
arguments: [!closure_proxy ['@closure_proxy', getBaz]]
alias_for_foo: '@foo'
alias_for_alias: '@foo'
Psr\Container\ContainerInterface:

View File

@ -4,7 +4,7 @@ CHANGELOG
3.3.0
-----
* The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure-proxy injection instead.
* The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure factories instead.
3.0.0
-----

View File

@ -160,7 +160,7 @@ class ContainerAwareEventDispatcher extends EventDispatcher
*/
public function addSubscriberService($serviceId, $class)
{
@trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use EventDispatcher with closure-proxy injection instead.', __CLASS__), E_USER_DEPRECATED);
@trigger_error(sprintf('The %s class is deprecated since version 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED);
foreach ($class::getSubscribedEvents() as $eventName => $params) {
if (is_string($params)) {

View File

@ -46,13 +46,7 @@ class WrappedListener
$this->name = is_object($listener[0]) ? get_class($listener[0]) : $listener[0];
$this->pretty = $this->name.'::'.$listener[1];
} elseif ($listener instanceof \Closure) {
$r = new \ReflectionFunction($listener);
if (preg_match('#^/\*\* @closure-proxy ([^: ]++)::([^: ]++) \*/$#', $r->getDocComment(), $m)) {
$this->name = $m[1];
$this->pretty = $m[1].'::'.$m[2];
} else {
$this->pretty = $this->name = 'closure';
}
$this->pretty = $this->name = 'closure';
} elseif (is_string($listener)) {
$this->pretty = $this->name = $listener;
} else {

View File

@ -38,10 +38,6 @@ class ClassStub extends ConstStub
if (null !== $callable) {
if ($callable instanceof \Closure) {
$r = new \ReflectionFunction($callable);
if (preg_match('#^/\*\* @closure-proxy ([^: ]++)::([^: ]++) \*/$#', $r->getDocComment(), $m)) {
$r = array($m[1], $m[2]);
}
} elseif (is_object($callable)) {
$r = array($callable, '__invoke');
} elseif (is_array($callable)) {