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 * @deprecated since version 3.3, to be removed in 4.0.
23 class FactoryReturnTypePass implements CompilerPassInterface
25 private $resolveClassPass;
27 public function __construct(ResolveClassPass $resolveClassPass = null)
29 if (null === $resolveClassPass) {
30 @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 3.3 and will be removed in 4.0.', E_USER_DEPRECATED);
32 $this->resolveClassPass = $resolveClassPass;
38 public function process(ContainerBuilder $container)
40 // works only since php 7.0 and hhvm 3.11
41 if (!method_exists(\ReflectionMethod::class, 'getReturnType')) {
44 $resolveClassPassChanges = null !== $this->resolveClassPass ? $this->resolveClassPass->getChanges() : array();
46 foreach ($container->getDefinitions() as $id => $definition) {
47 $this->updateDefinition($container, $id, $definition, $resolveClassPassChanges);
51 private function updateDefinition(ContainerBuilder $container, $id, Definition $definition, array $resolveClassPassChanges, array $previous = array())
54 if (isset($previous[$id])) {
58 $factory = $definition->getFactory();
59 if (null === $factory || (!isset($resolveClassPassChanges[$id]) && null !== $definition->getClass())) {
64 if (\is_string($factory)) {
66 $m = new \ReflectionFunction($factory);
67 if (false !== $m->getFileName() && file_exists($m->getFileName())) {
68 $container->fileExists($m->getFileName());
70 } catch (\ReflectionException $e) {
74 if ($factory[0] instanceof Reference) {
75 $previous[$id] = true;
76 $factoryId = $container->normalizeId($factory[0]);
77 $factoryDefinition = $container->findDefinition($factoryId);
78 $this->updateDefinition($container, $factoryId, $factoryDefinition, $resolveClassPassChanges, $previous);
79 $class = $factoryDefinition->getClass();
84 if (!$m = $container->getReflectionClass($class, false)) {
88 $m = $m->getMethod($factory[1]);
89 } catch (\ReflectionException $e) {
94 $returnType = $m->getReturnType();
95 if (null !== $returnType && !$returnType->isBuiltin()) {
96 $returnType = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType->__toString();
97 if (null !== $class) {
98 $declaringClass = $m->getDeclaringClass()->getName();
99 if ('self' === strtolower($returnType)) {
100 $returnType = $declaringClass;
101 } elseif ('parent' === strtolower($returnType)) {
102 $returnType = get_parent_class($declaringClass) ?: null;
106 if (null !== $returnType && (!isset($resolveClassPassChanges[$id]) || $returnType !== $resolveClassPassChanges[$id])) {
107 @trigger_error(sprintf('Relying on its factory\'s return-type to define the class of service "%s" is deprecated since Symfony 3.3 and won\'t work in 4.0. Set the "class" attribute to "%s" on the service definition instead.', $id, $returnType), E_USER_DEPRECATED);
109 $definition->setClass($returnType);