8000 [DI] Refacto / cleanup / minor fixes by nicolas-grekas · Pull Request #21561 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DI] Refacto / cleanup / minor fixes #21561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Fai 10000 led to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/Symfony/Component/DependencyInjection/ChildDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,11 @@ public function setDeprecated($boolean = true, $template = null)
/**
* {@inheritdoc}
*/
public function setAutowiredMethods(array $autowiredMethods)
public function setAutowiredCalls(array $autowiredCalls)
{
$this->changes['autowired_methods'] = true;
$this->changes['autowired_calls'] = true;

return parent::setAutowiredMethods($autowiredMethods);
return parent::setAutowiredCalls($autowiredCalls);
}

/**
Expand Down
62 changes: 38 additions & 24 deletions src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@
*/
class AutowirePass extends AbstractRecursivePass
{
/**
* @internal
*/
const MODE_REQUIRED = 1;

/**
* @internal
*/
const MODE_OPTIONAL = 2;

private $definedTypes = array();
private $types;
private $ambiguousServiceTypes = array();
Expand Down Expand Up @@ -72,15 +82,15 @@ public static function createResourceForClass(\ReflectionClass $reflectionClass)
*/
protected function processValue($value, $isRoot = false)
{
if (!$value instanceof Definition || !$autowiredMethods = $value->getAutowiredMethods()) {
if (!$value instanceof Definition || !$value->getAutowiredCalls()) {
return parent::processValue($value, $isRoot);
}

if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
return parent::processValue($value, $isRoot);
}

$autowiredMethods = $this->getMethodsToAutowire($reflectionClass, $autowiredMethods);
$autowiredMethods = $this->getMethodsToAutowire($reflectionClass, $value->getAutowiredCalls());
$methodCalls = $value->getMethodCalls();

if ($constructor = $reflectionClass->getConstructor()) {
Expand All @@ -89,7 +99,7 @@ protected function processValue($value, $isRoot = false)
throw new RuntimeException(sprintf('Cannot autowire service "%s": class %s has no constructor but arguments are defined.', $this->currentId, $reflectionClass->name, $method));
}

$methodCalls = $this->autowireMethodCalls($reflectionClass, $methodCalls, $autowiredMethods);
$methodCalls = $this->autowireCalls($reflectionClass, $methodCalls, $autowiredMethods);
$overriddenGetters = $this->autowireOverridenGetters($value->getOverriddenGetters(), $autowiredMethods);

if ($constructor) {
Expand Down Expand Up @@ -125,6 +135,14 @@ private function getMethodsToAutowire(\ReflectionClass $reflectionClass, array $
$regexList = array();
$methodsToAutowire = array();

if ($reflectionMethod = $reflectionClass->getConstructor()) {
$methodsToAutowire[$lcMethod = strtolower($reflectionMethod->name)] = $reflectionMethod;
unset($autowiredMethods['__construct']);
}
if (!$autowiredMethods) {
return $methodsToAutowire;
}

foreach ($autowiredMethods as $pattern) {
$regexList[] = '/^'.str_replace('\*', '.*', preg_quote($pattern, '/')).'$/i';
}
Expand All @@ -141,10 +159,6 @@ private function getMethodsToAutowire(\ReflectionClass $reflectionClass, array $
continue 2;
}
}

if ($reflectionMethod->isConstructor()) {
$methodsToAutowire[strtolower($reflectionMethod->name)] = $reflectionMethod;
}
}

if ($notFound = array_diff($autowiredMethods, $found)) {
Expand All @@ -161,13 +175,10 @@ private function getMethodsToAutowire(\ReflectionClass $reflectionClass, array $
*
* @return array
*/
private function autowireMethodCalls(\ReflectionClass $reflectionClass, array $methodCalls, array $autowiredMethods)
private function autowireCalls(\ReflectionClass $reflectionClass, array $methodCalls, array $autowiredMethods)
{
$parameterBag = $this->container->getParameterBag();

foreach ($methodCalls as $i => $call) {
list($method, $arguments) = $call;
$method = $parameterBag->resolveValue($method);

if (isset($autowiredMethods[$lcMethod = strtolower($method)]) && $autowiredMethods[$lcMethod]->isPublic()) {
$reflectionMethod = $autowiredMethods[$lcMethod];
Expand All @@ -182,15 +193,15 @@ private function autowireMethodCalls(\ReflectionClass $reflectionClass, array $m
}
}

$arguments = $this->autowireMethodCall($reflectionMethod, $arguments, true);
$arguments = $this->autowireMethod($reflectionMethod, $arguments, self::MODE_REQUIRED);

if ($arguments !== $call[1]) {
$methodCalls[$i][1] = $arguments;
}
}

foreach ($autowiredMethods as $reflectionMethod) {
if ($reflectionMethod->isPublic() && $arguments = $this->autowireMethodCall($reflectionMethod, array(), false)) {
foreach ($autowiredMethods as $lcMethod => $reflectionMethod) {
if ($reflectionMethod->isPublic() && $arguments = $this->autowireMethod($reflectionMethod, array(), self::MODE_OPTIONAL)) {
$methodCalls[] = array($reflectionMethod->name, $arguments);
}
}
Expand All @@ -203,19 +214,22 @@ private function autowireMethodCalls(\ReflectionClass $reflectionClass, array $m
*
* @param \ReflectionMethod $reflectionMethod
* @param array $arguments
* @param bool $mustAutowire
* @param int $mode
*
* @return array The autowired arguments
*
* @throws RuntimeException
*/
private function autowireMethodCall(\ReflectionMethod $reflectionMethod, array $arguments, $mustAutowire)
private function autowireMethod(\ReflectionMethod $reflectionMethod, array $arguments, $mode)
{
$didAutowire = false; // Whether any arguments have been autowired or not
foreach ($reflectionMethod->getParameters() as $index => $parameter) {
if (array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
continue;
}
if (method_exists($parameter, 'isVariadic') && $parameter->isVariadic()) {
continue;
}

if (method_exists($parameter, 'getType')) {
if ($typeName = $parameter->getType()) {
Expand All @@ -228,7 +242,7 @@ private function autowireMethodCall(\ReflectionMethod $reflectionMethod, array $
if (!$typeName) {
// no default value? Then fail
if (!$parameter->isOptional()) {
if ($mustAutowire) {
if (self::MODE_REQUIRED === $mode) {
throw new RuntimeException(sprintf('Cannot autowire service "%s": argument $%s of method %s::%s() must have a type-hint or be given a value explicitly.', $this->currentId, $parameter->name, $reflectionMethod->class, $reflectionMethod->name));
}

Expand Down Expand Up @@ -268,7 +282,7 @@ private function autowireMethodCall(\ReflectionMethod $reflectionMethod, array $
$value = $parameter->getDefaultValue();
} else {
// The exception code is set to 1 if the exception must be thrown even if it's an optional setter
if (1 === $e->getCode() || $mustAutowire) {
if (1 === $e->getCode() || self::MODE_REQUIRED === $mode) {
throw $e;
}

Expand All @@ -279,7 +293,7 @@ private function autowireMethodCall(\ReflectionMethod $reflectionMethod, array $
// Typehint against a non-existing class

if (!$parameter->isDefaultValueAvailable()) {
if ($mustAutowire) {
if (self::MODE_REQUIRED === $mode) {
throw new RuntimeException(sprintf('Cannot autowire argument $%s of method %s::%s() for service "%s": Class %s does not exist.', $parameter->name, $reflectionMethod->class, $reflectionMethod->name, $this->currentId, $typeName));
}

Expand All @@ -292,7 +306,7 @@ private function autowireMethodCall(\ReflectionMethod $reflectionMethod, array $
$arguments[$index] = $value;
}

if (!$mustAutowire && !$didAutowire) {
if (self::MODE_REQUIRED !== $mode && !$didAutowire) {
return array();
}

Expand All @@ -313,8 +327,8 @@ private function autowireMethodCall(\ReflectionMethod $reflectionMethod, array $
*/
private function autowireOverridenGetters(array $overridenGetters, array $autowiredMethods)
{
foreach ($autowiredMethods as $reflectionMethod) {
if (isset($overridenGetters[strtolower($reflectionMethod->name)])
foreach ($autowiredMethods as $lcMethod => $reflectionMethod) {
if (isset($overridenGetters[$lcMethod])
|| !method_exists($reflectionMethod, 'getReturnType')
|| 0 !== $reflectionMethod->getNumberOfParameters()
|| $reflectionMethod->isFinal()
Expand All @@ -326,7 +340,7 @@ private function autowireOverridenGetters(array $overridenGetters, array $autowi
$typeName = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType->__toString();

if ($this->container->has($typeName) && !$this->container->findDefinition($typeName)->isAbstract()) {
$overridenGetters[$reflectionMethod->name] = new Reference($typeName);
$overridenGetters[$lcMethod] = new Reference($typeName);
continue;
}

Expand All @@ -346,7 +360,7 @@ private function autowireOverridenGetters(array $overridenGetters, array $autowi
continue;
}

$overridenGetters[$reflectionMethod->name] = $value;
$overridenGetters[$lcMethod] = $value;
}

return $overridenGetters;
Expand Down
10000
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private function doResolveDefinition(ChildDefinition $definition)
$def->setFile($parentDef->getFile());
$def->setPublic($parentDef->isPublic());
$def->setLazy($parentDef->isLazy());
$def->setAutowiredMethods($parentDef->getAutowiredMethods());
$def->setAutowiredCalls($parentDef->getAutowiredCalls());

// overwrite with values specified in the decorator
$changes = $definition->getChanges();
Expand All @@ -126,8 +126,8 @@ private function doResolveDefinition(ChildDefinition $definition)
if (isset($changes['deprecated'])) {
$def->setDeprecated($definition->isDeprecated(), $definition->getDeprecationMessage('%service_id%'));
}
if (isset($changes['autowired_methods'])) {
$def->setAutowiredMethods($definition->getAutowiredMethods());
if (isset($changes['autowired_calls'])) {
$def->setAutowiredCalls($definition->getAutowiredCalls());
}
if (isset($changes['decorated_service'])) {
$decoratedService = $definition->getDecoratedService();
Expand Down
91 changes: 17 additions & 74 deletions src/Symfony/Component/DependencyInjection/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
use Symfony\Component\DependencyInjection\LazyProxy\GetterProxyInterface;
use Symfony\Component\DependencyInjection\LazyProxy\InheritanceProxyHelper;
use Symfony\Component\DependencyInjection\LazyProxy\InheritanceProxyInterface;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;

Expand Down Expand Up @@ -1022,7 +1023,7 @@ private function createService(Definition $definition, $id, $tryProxy = true)
if (null === $salt) {
$salt = str_replace('.', '', uniqid('', true));
}
$service = sprintf('%s implements \\%s { private $container%4$s; private $values%4$s; %s }', $r->name, GetterProxyInterface::class, $this->generateOverriddenGetters($id, $definition, $r, $salt), $salt);
$service = sprintf('%s implements \\%s { private $container%4$s; private $getters%4$s; %s }', $r->name, InheritanceProxyInterface::class, $this->generateOverriddenMethods($id, $definition, $r, $salt), $salt);
if (!class_exists($proxyClass = 'SymfonyProxy_'.md5($service), false)) {
eval(sprintf('class %s extends %s', $proxyClass, $service));
}
Expand All @@ -1032,7 +1033,7 @@ private function createService(Definition $definition, $id, $tryProxy = true)
$constructor = null;
}
$service = $constructor ? $r->newInstanceWithoutConstructor() : $r->newInstanceArgs($arguments);
call_user_func(\Closure::bind(function ($c, $v, $s) { $this->{'container'.$s} = $c; $this->{'values'.$s} = $v; }, $service, $service), $this, $definition->getOverriddenGetters(), $salt);
call_user_func(\Closure::bind(function ($c, $g, $s) { $this->{'container'.$s} = $c; $this->{'getters'.$s} = $g; }, $service, $service), $this, $definition->getOverriddenGetters(), $salt);
if ($constructor) {
$constructor->invokeArgs($service, $arguments);
}
Expand Down Expand Up @@ -1294,22 +1295,29 @@ public function getEnvCounters()
return $this->envCounters;
}

private function generateOverriddenGetters($id, Definition $definition, \ReflectionClass $class, $salt)
private function generateOverriddenMethods($id, Definition $definition, \ReflectionClass $class, $salt)
{
if ($class->isFinal()) {
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": class "%s" cannot be marked as final.', $id, $class->name));
throw new RuntimeException(sprintf('Unable to configure service "%s": class "%s" cannot be marked as final.', $id, $class->name));
}

return $this->generateOverriddenGetters($id, $definition, $class, $salt);
}

private function generateOverriddenGetters($id, Definition $definition, \ReflectionClass $class, $salt)
{
$getters = '';

foreach ($definition->getOverriddenGetters() as $name => $returnValue) {
$r = self::getGetterReflector($class, $name, $id, $type);
$r = InheritanceProxyHelper::getGetterReflector($class, $name, $id);
$signature = InheritanceProxyHelper::getSignature($r);
$visibility = $r->isProtected() ? 'protected' : 'public';
$name = var_export($name, true);
$getters .= <<<EOF

{$visibility} function {$r->name}(){$type} {
{$visibility} function {$signature} {
\$c = \$this->container{$salt};
\$b = \$c->getParameterBag();
\$v = \$this->values{$salt}[{$name}];
\$v = \$this->getters{$salt}['{$name}'];

foreach (\$c->getServiceConditionals(\$v) as \$s) {
if (!\$c->has(\$s)) {
Expand All @@ -1325,71 +1333,6 @@ private function generateOverriddenGetters($id, Definition $definition, \Reflect
return $getters;
}

/**
* @internal
*/
public static function getGetterReflector(\ReflectionClass $class, $name, $id, &$type)
{
if (!$class->hasMethod($name)) {
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" does not exist.', $id, $class->name, $name));
}
$r = $class->getMethod($name);
if ($r->isPrivate()) {
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" must be public or protected.', $id, $class->name, $r->name));
}
if ($r->isStatic()) {
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" cannot be static.', $id, $class->name, $r->name));
}
if ($r->isFinal()) {
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" cannot be marked as final.', $id, $class->name, $r->name));
}
if ($r->returnsReference()) {
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" cannot return by reference.', $id, $class->name, $r->name));
}
if (0 < $r->getNumberOfParameters()) {
throw new RuntimeException(sprintf('Unable to configure getter injection for service "%s": method "%s::%s" cannot have any arguments.', $id, $class->name, $r->name));
}
if ($type = method_exists($r, 'getReturnType') ? $r->getReturnType() : null) {
$type = ': '.($type->allowsNull() ? '?' : '').self::generateTypeHint($type, $r);
}

return $r;
}

/**
* @internal
*/
public static function generateTypeHint($type, \ReflectionFunctionAbstract $r)
{
if (is_string($type)) {
$name = $type;

if ('callable' === $name || 'array' === $name) {
return $name;
}
} else {
$name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString();

if ($type->isBuiltin()) {
return $name;
}
}
$lcName = strtolower($name);

if ('self' !== $lcName && 'parent' !== $lcName) {
return '\\'.$name;
}
if (!$r instanceof \ReflectionMethod) {
return;
}
if ('self' === $lcName) {
return '\\'.$r->getDeclaringClass()->name;
}
if ($parent = $r->getDeclaringClass()->getParentClass()) {
return '\\'.$parent->name;
}
}

/**
* @internal
*/
Expand Down
Loading
0