4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\DependencyInjection\Compiler;
14 use Symfony\Component\DependencyInjection\ContainerBuilder;
15 use Symfony\Component\DependencyInjection\Definition;
16 use Symfony\Component\DependencyInjection\Reference;
19 * @author Guilhem N. <egetick@gmail.com>
21 class FactoryReturnTypePass implements CompilerPassInterface
26 public function process(ContainerBuilder $container)
28 // works only since php 7.0 and hhvm 3.11
29 if (!method_exists(\ReflectionMethod::class, 'getReturnType')) {
33 foreach ($container->getDefinitions() as $id => $definition) {
34 $this->updateDefinition($container, $id, $definition);
38 private function updateDefinition(ContainerBuilder $container, $id, Definition $definition, array $previous = array())
41 if (isset($previous[$id])) {
45 $factory = $definition->getFactory();
46 if (null === $factory || null !== $definition->getClass()) {
51 if (is_string($factory)) {
53 $m = new \ReflectionFunction($factory);
54 } catch (\ReflectionException $e) {
58 if ($factory[0] instanceof Reference) {
59 $previous[$id] = true;
60 $factoryDefinition = $container->findDefinition((string) $factory[0]);
61 $this->updateDefinition($container, strtolower($factory[0]), $factoryDefinition, $previous);
62 $class = $factoryDefinition->getClass();
68 $m = new \ReflectionMethod($class, $factory[1]);
69 } catch (\ReflectionException $e) {
74 $returnType = $m->getReturnType();
75 if (null !== $returnType && !$returnType->isBuiltin()) {
76 $returnType = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType->__toString();
77 if (null !== $class) {
78 $declaringClass = $m->getDeclaringClass()->getName();
79 if ('self' === strtolower($returnType)) {
80 $returnType = $declaringClass;
81 } elseif ('parent' === strtolower($returnType)) {
82 $returnType = get_parent_class($declaringClass) ?: null;
86 $definition->setClass($returnType);