diff --git a/src/DI/Resolver.php b/src/DI/Resolver.php index 6201c3276..b3b1aa2cd 100644 --- a/src/DI/Resolver.php +++ b/src/DI/Resolver.php @@ -484,7 +484,29 @@ public static function autowireArguments(\ReflectionFunctionAbstract $method, ar foreach ($method->getParameters() as $num => $param) { $paramName = $param->name; - if (!$param->isVariadic() && array_key_exists($paramName, $arguments)) { + if ($param->isVariadic()) { + if (array_key_exists($paramName, $arguments)) { + $values = (array) $arguments[$paramName]; + } elseif (array_key_exists($num, $arguments)) { + $values = array_slice($arguments, $num, null, true); + ksort($values); + } else { + $values = (array) self::autowireArgument($param, $getter); + } + + $valueNum = $num; + foreach ($values as $value) { + $res[$valueNum] = $value; + unset($arguments[$valueNum]); + $valueNum++; + } + + unset($arguments[$paramName]); + if ($valueNum > $num) { + $num = $valueNum - 1; + } + + } elseif (array_key_exists($paramName, $arguments)) { $res[$num] = $arguments[$paramName]; unset($arguments[$paramName], $arguments[$num]); @@ -496,7 +518,7 @@ public static function autowireArguments(\ReflectionFunctionAbstract $method, ar $res[$num] = self::autowireArgument($param, $getter); } - $optCount = $param->isOptional() && $res[$num] === ($param->isDefaultValueAvailable() ? Reflection::getParameterDefaultValue($param) : null) + $optCount = ($param->isVariadic() && !array_key_exists($num, $res)) || ($param->isOptional() && $res[$num] === ($param->isDefaultValueAvailable() ? Reflection::getParameterDefaultValue($param) : null)) ? $optCount + 1 : 0; } @@ -531,7 +553,7 @@ private static function autowireArgument(\ReflectionParameter $parameter, callab if ($type && !Reflection::isBuiltinType($type)) { try { - $res = $getter($type, true); + $res = $getter($type, !$parameter->isVariadic()); } catch (MissingServiceException $e) { $res = null; } catch (ServiceCreationException $e) { diff --git a/tests/DI/ContainerBuilder.autowiring.variadic.phpt b/tests/DI/ContainerBuilder.autowiring.variadic.phpt new file mode 100644 index 000000000..401d558a2 --- /dev/null +++ b/tests/DI/ContainerBuilder.autowiring.variadic.phpt @@ -0,0 +1,84 @@ +bars = $bars; + } +} + +class Service +{ +} + +class ServiceChild extends Service +{ +} + + +$builder = new DI\ContainerBuilder; + +$builder->addDefinition('foo') + ->setType('Foo'); +$builder->addDefinition('s1') + ->setType('Service'); +$builder->addDefinition('s2') + ->setType('Service'); +$builder->addDefinition('s3') + ->setType('ServiceChild'); +$builder->addDefinition('s4') + ->setType('stdClass'); +$builder->addDefinition('s5') + ->setType('Service') + ->setAutowired(false); +$builder->addDefinition('fooWithExplicitBars') + ->setType('Foo') + ->setArgument('bars', [ + $builder->getDefinition('s3'), + $builder->getDefinition('s5'), + ]); + +$container = createContainer($builder); + +$foo = $container->getService('foo'); +Assert::type(Foo::class, $foo); +Assert::same([ + $container->getService('s1'), + $container->getService('s2'), + $container->getService('s3'), +], $foo->bars); + +$fooWithExplicitBars = $container->getService('fooWithExplicitBars'); +Assert::type(Foo::class, $fooWithExplicitBars); +Assert::same([ + $container->getService('s3'), + $container->getService('s5'), +], $fooWithExplicitBars->bars); + + +// runtime + +$foo2 = $container->createInstance('Foo'); +Assert::type(Foo::class, $foo2); +Assert::same([ + $container->getService('s1'), + $container->getService('s2'), + $container->getService('s3'), +], $foo2->bars); diff --git a/tests/DI/Resolver.autowireArguments.phpt b/tests/DI/Resolver.autowireArguments.phpt index aeae56194..a2e8b8aac 100644 --- a/tests/DI/Resolver.autowireArguments.phpt +++ b/tests/DI/Resolver.autowireArguments.phpt @@ -23,6 +23,11 @@ class Test public function methodNullable(?self $class, ?self $self, ?Undefined $nullable1, ?int $nullable2) { } + + + public function methodVariadic(self ...$variadic) + { + } } Assert::equal( @@ -38,3 +43,24 @@ Assert::equal( return $type === 'Test' ? new Test : null; }) ); + +Assert::equal( + [new Test, new Test], + Resolver::autowireArguments(new ReflectionMethod('Test', 'methodVariadic'), [], function ($type) { + return $type === 'Test' ? [new Test, new Test] : []; + }) +); + +Assert::equal( + [new Test, new Test, new Test], + Resolver::autowireArguments(new ReflectionMethod('Test', 'methodVariadic'), [new Test, new Test, new Test], function ($type) { + return []; + }) +); + +Assert::equal( + [new Test, new Test, new Test], + Resolver::autowireArguments(new ReflectionMethod('Test', 'methodVariadic'), ['variadic' => [new Test, new Test, new Test]], function ($type) { + return []; + }) +);