vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/ContainerBuilder.php line 1512

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\DependencyInjection;
  11. use Psr\Container\ContainerInterface as PsrContainerInterface;
  12. use Symfony\Component\Config\Resource\ClassExistenceResource;
  13. use Symfony\Component\Config\Resource\ComposerResource;
  14. use Symfony\Component\Config\Resource\DirectoryResource;
  15. use Symfony\Component\Config\Resource\FileExistenceResource;
  16. use Symfony\Component\Config\Resource\FileResource;
  17. use Symfony\Component\Config\Resource\GlobResource;
  18. use Symfony\Component\Config\Resource\ReflectionClassResource;
  19. use Symfony\Component\Config\Resource\ResourceInterface;
  20. use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
  21. use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
  22. use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
  23. use Symfony\Component\DependencyInjection\Compiler\Compiler;
  24. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  25. use Symfony\Component\DependencyInjection\Compiler\PassConfig;
  26. use Symfony\Component\DependencyInjection\Compiler\ResolveEnvPlaceholdersPass;
  27. use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
  28. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  29. use Symfony\Component\DependencyInjection\Exception\LogicException;
  30. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  31. use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
  32. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  33. use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
  34. use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
  35. use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
  36. use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
  37. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
  38. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  39. use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
  40. use Symfony\Component\ExpressionLanguage\Expression;
  41. use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
  42. /**
  43.  * ContainerBuilder is a DI container that provides an API to easily describe services.
  44.  *
  45.  * @author Fabien Potencier <fabien@symfony.com>
  46.  */
  47. class ContainerBuilder extends Container implements TaggedContainerInterface
  48. {
  49.     /**
  50.      * @var ExtensionInterface[]
  51.      */
  52.     private $extensions = [];
  53.     /**
  54.      * @var ExtensionInterface[]
  55.      */
  56.     private $extensionsByNs = [];
  57.     /**
  58.      * @var Definition[]
  59.      */
  60.     private $definitions = [];
  61.     /**
  62.      * @var Alias[]
  63.      */
  64.     private $aliasDefinitions = [];
  65.     /**
  66.      * @var ResourceInterface[]
  67.      */
  68.     private $resources = [];
  69.     private $extensionConfigs = [];
  70.     /**
  71.      * @var Compiler
  72.      */
  73.     private $compiler;
  74.     private $trackResources;
  75.     /**
  76.      * @var InstantiatorInterface|null
  77.      */
  78.     private $proxyInstantiator;
  79.     /**
  80.      * @var ExpressionLanguage|null
  81.      */
  82.     private $expressionLanguage;
  83.     /**
  84.      * @var ExpressionFunctionProviderInterface[]
  85.      */
  86.     private $expressionLanguageProviders = [];
  87.     /**
  88.      * @var string[] with tag names used by findTaggedServiceIds
  89.      */
  90.     private $usedTags = [];
  91.     /**
  92.      * @var string[][] a map of env var names to their placeholders
  93.      */
  94.     private $envPlaceholders = [];
  95.     /**
  96.      * @var int[] a map of env vars to their resolution counter
  97.      */
  98.     private $envCounters = [];
  99.     /**
  100.      * @var string[] the list of vendor directories
  101.      */
  102.     private $vendors;
  103.     private $autoconfiguredInstanceof = [];
  104.     private $removedIds = [];
  105.     private $removedBindingIds = [];
  106.     private static $internalTypes = [
  107.         'int' => true,
  108.         'float' => true,
  109.         'string' => true,
  110.         'bool' => true,
  111.         'resource' => true,
  112.         'object' => true,
  113.         'array' => true,
  114.         'null' => true,
  115.         'callable' => true,
  116.         'iterable' => true,
  117.         'mixed' => true,
  118.     ];
  119.     public function __construct(ParameterBagInterface $parameterBag null)
  120.     {
  121.         parent::__construct($parameterBag);
  122.         $this->trackResources interface_exists('Symfony\Component\Config\Resource\ResourceInterface');
  123.         $this->setDefinition('service_container', (new Definition(ContainerInterface::class))->setSynthetic(true)->setPublic(true));
  124.         $this->setAlias(PsrContainerInterface::class, new Alias('service_container'false));
  125.         $this->setAlias(ContainerInterface::class, new Alias('service_container'false));
  126.     }
  127.     /**
  128.      * @var \ReflectionClass[] a list of class reflectors
  129.      */
  130.     private $classReflectors;
  131.     /**
  132.      * Sets the track resources flag.
  133.      *
  134.      * If you are not using the loaders and therefore don't want
  135.      * to depend on the Config component, set this flag to false.
  136.      *
  137.      * @param bool $track True if you want to track resources, false otherwise
  138.      */
  139.     public function setResourceTracking($track)
  140.     {
  141.         $this->trackResources = (bool) $track;
  142.     }
  143.     /**
  144.      * Checks if resources are tracked.
  145.      *
  146.      * @return bool true If resources are tracked, false otherwise
  147.      */
  148.     public function isTrackingResources()
  149.     {
  150.         return $this->trackResources;
  151.     }
  152.     /**
  153.      * Sets the instantiator to be used when fetching proxies.
  154.      */
  155.     public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator)
  156.     {
  157.         $this->proxyInstantiator $proxyInstantiator;
  158.     }
  159.     public function registerExtension(ExtensionInterface $extension)
  160.     {
  161.         $this->extensions[$extension->getAlias()] = $extension;
  162.         if (false !== $extension->getNamespace()) {
  163.             $this->extensionsByNs[$extension->getNamespace()] = $extension;
  164.         }
  165.     }
  166.     /**
  167.      * Returns an extension by alias or namespace.
  168.      *
  169.      * @param string $name An alias or a namespace
  170.      *
  171.      * @return ExtensionInterface An extension instance
  172.      *
  173.      * @throws LogicException if the extension is not registered
  174.      */
  175.     public function getExtension($name)
  176.     {
  177.         if (isset($this->extensions[$name])) {
  178.             return $this->extensions[$name];
  179.         }
  180.         if (isset($this->extensionsByNs[$name])) {
  181.             return $this->extensionsByNs[$name];
  182.         }
  183.         throw new LogicException(sprintf('Container extension "%s" is not registered'$name));
  184.     }
  185.     /**
  186.      * Returns all registered extensions.
  187.      *
  188.      * @return ExtensionInterface[] An array of ExtensionInterface
  189.      */
  190.     public function getExtensions()
  191.     {
  192.         return $this->extensions;
  193.     }
  194.     /**
  195.      * Checks if we have an extension.
  196.      *
  197.      * @param string $name The name of the extension
  198.      *
  199.      * @return bool If the extension exists
  200.      */
  201.     public function hasExtension($name)
  202.     {
  203.         return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]);
  204.     }
  205.     /**
  206.      * Returns an array of resources loaded to build this configuration.
  207.      *
  208.      * @return ResourceInterface[] An array of resources
  209.      */
  210.     public function getResources()
  211.     {
  212.         return array_values($this->resources);
  213.     }
  214.     /**
  215.      * @return $this
  216.      */
  217.     public function addResource(ResourceInterface $resource)
  218.     {
  219.         if (!$this->trackResources) {
  220.             return $this;
  221.         }
  222.         if ($resource instanceof GlobResource && $this->inVendors($resource->getPrefix())) {
  223.             return $this;
  224.         }
  225.         $this->resources[(string) $resource] = $resource;
  226.         return $this;
  227.     }
  228.     /**
  229.      * Sets the resources for this configuration.
  230.      *
  231.      * @param ResourceInterface[] $resources An array of resources
  232.      *
  233.      * @return $this
  234.      */
  235.     public function setResources(array $resources)
  236.     {
  237.         if (!$this->trackResources) {
  238.             return $this;
  239.         }
  240.         $this->resources $resources;
  241.         return $this;
  242.     }
  243.     /**
  244.      * Adds the object class hierarchy as resources.
  245.      *
  246.      * @param object|string $object An object instance or class name
  247.      *
  248.      * @return $this
  249.      */
  250.     public function addObjectResource($object)
  251.     {
  252.         if ($this->trackResources) {
  253.             if (\is_object($object)) {
  254.                 $object = \get_class($object);
  255.             }
  256.             if (!isset($this->classReflectors[$object])) {
  257.                 $this->classReflectors[$object] = new \ReflectionClass($object);
  258.             }
  259.             $class $this->classReflectors[$object];
  260.             foreach ($class->getInterfaceNames() as $name) {
  261.                 if (null === $interface = &$this->classReflectors[$name]) {
  262.                     $interface = new \ReflectionClass($name);
  263.                 }
  264.                 $file $interface->getFileName();
  265.                 if (false !== $file && file_exists($file)) {
  266.                     $this->fileExists($file);
  267.                 }
  268.             }
  269.             do {
  270.                 $file $class->getFileName();
  271.                 if (false !== $file && file_exists($file)) {
  272.                     $this->fileExists($file);
  273.                 }
  274.                 foreach ($class->getTraitNames() as $name) {
  275.                     $this->addObjectResource($name);
  276.                 }
  277.             } while ($class $class->getParentClass());
  278.         }
  279.         return $this;
  280.     }
  281.     /**
  282.      * Adds the given class hierarchy as resources.
  283.      *
  284.      * @return $this
  285.      *
  286.      * @deprecated since version 3.3, to be removed in 4.0. Use addObjectResource() or getReflectionClass() instead.
  287.      */
  288.     public function addClassResource(\ReflectionClass $class)
  289.     {
  290.         @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the addObjectResource() or the getReflectionClass() method instead.'E_USER_DEPRECATED);
  291.         return $this->addObjectResource($class->name);
  292.     }
  293.     /**
  294.      * Retrieves the requested reflection class and registers it for resource tracking.
  295.      *
  296.      * @param string $class
  297.      * @param bool   $throw
  298.      *
  299.      * @return \ReflectionClass|null
  300.      *
  301.      * @throws \ReflectionException when a parent class/interface/trait is not found and $throw is true
  302.      *
  303.      * @final
  304.      */
  305.     public function getReflectionClass($class$throw true)
  306.     {
  307.         if (!$class $this->getParameterBag()->resolveValue($class)) {
  308.             return null;
  309.         }
  310.         if (isset(self::$internalTypes[$class])) {
  311.             return null;
  312.         }
  313.         $resource null;
  314.         try {
  315.             if (isset($this->classReflectors[$class])) {
  316.                 $classReflector $this->classReflectors[$class];
  317.             } elseif (class_exists(ClassExistenceResource::class)) {
  318.                 $resource = new ClassExistenceResource($classfalse);
  319.                 $classReflector $resource->isFresh(0) ? false : new \ReflectionClass($class);
  320.             } else {
  321.                 $classReflector class_exists($class) ? new \ReflectionClass($class) : false;
  322.             }
  323.         } catch (\ReflectionException $e) {
  324.             if ($throw) {
  325.                 throw $e;
  326.             }
  327.             $classReflector false;
  328.         }
  329.         if ($this->trackResources) {
  330.             if (!$classReflector) {
  331.                 $this->addResource($resource ?: new ClassExistenceResource($classfalse));
  332.             } elseif (!$classReflector->isInternal()) {
  333.                 $path $classReflector->getFileName();
  334.                 if (!$this->inVendors($path)) {
  335.                     $this->addResource(new ReflectionClassResource($classReflector$this->vendors));
  336.                 }
  337.             }
  338.             $this->classReflectors[$class] = $classReflector;
  339.         }
  340.         return $classReflector ?: null;
  341.     }
  342.     /**
  343.      * Checks whether the requested file or directory exists and registers the result for resource tracking.
  344.      *
  345.      * @param string      $path          The file or directory path for which to check the existence
  346.      * @param bool|string $trackContents Whether to track contents of the given resource. If a string is passed,
  347.      *                                   it will be used as pattern for tracking contents of the requested directory
  348.      *
  349.      * @return bool
  350.      *
  351.      * @final
  352.      */
  353.     public function fileExists($path$trackContents true)
  354.     {
  355.         $exists file_exists($path);
  356.         if (!$this->trackResources || $this->inVendors($path)) {
  357.             return $exists;
  358.         }
  359.         if (!$exists) {
  360.             $this->addResource(new FileExistenceResource($path));
  361.             return $exists;
  362.         }
  363.         if (is_dir($path)) {
  364.             if ($trackContents) {
  365.                 $this->addResource(new DirectoryResource($path, \is_string($trackContents) ? $trackContents null));
  366.             } else {
  367.                 $this->addResource(new GlobResource($path'/*'false));
  368.             }
  369.         } elseif ($trackContents) {
  370.             $this->addResource(new FileResource($path));
  371.         }
  372.         return $exists;
  373.     }
  374.     /**
  375.      * Loads the configuration for an extension.
  376.      *
  377.      * @param string $extension The extension alias or namespace
  378.      * @param array  $values    An array of values that customizes the extension
  379.      *
  380.      * @return $this
  381.      *
  382.      * @throws BadMethodCallException When this ContainerBuilder is compiled
  383.      * @throws \LogicException        if the extension is not registered
  384.      */
  385.     public function loadFromExtension($extension, array $values null)
  386.     {
  387.         if ($this->isCompiled()) {
  388.             throw new BadMethodCallException('Cannot load from an extension on a compiled container.');
  389.         }
  390.         if (\func_num_args() < 2) {
  391.             $values = [];
  392.         }
  393.         $namespace $this->getExtension($extension)->getAlias();
  394.         $this->extensionConfigs[$namespace][] = $values;
  395.         return $this;
  396.     }
  397.     /**
  398.      * Adds a compiler pass.
  399.      *
  400.      * @param CompilerPassInterface $pass     A compiler pass
  401.      * @param string                $type     The type of compiler pass
  402.      * @param int                   $priority Used to sort the passes
  403.      *
  404.      * @return $this
  405.      */
  406.     public function addCompilerPass(CompilerPassInterface $pass$type PassConfig::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/)
  407.     {
  408.         if (\func_num_args() >= 3) {
  409.             $priority func_get_arg(2);
  410.         } else {
  411.             if (__CLASS__ !== \get_class($this)) {
  412.                 $r = new \ReflectionMethod($this__FUNCTION__);
  413.                 if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
  414.                     @trigger_error(sprintf('Method %s() will have a third `int $priority = 0` argument in version 4.0. Not defining it is deprecated since Symfony 3.2.'__METHOD__), E_USER_DEPRECATED);
  415.                 }
  416.             }
  417.             $priority 0;
  418.         }
  419.         $this->getCompiler()->addPass($pass$type$priority);
  420.         $this->addObjectResource($pass);
  421.         return $this;
  422.     }
  423.     /**
  424.      * Returns the compiler pass config which can then be modified.
  425.      *
  426.      * @return PassConfig The compiler pass config
  427.      */
  428.     public function getCompilerPassConfig()
  429.     {
  430.         return $this->getCompiler()->getPassConfig();
  431.     }
  432.     /**
  433.      * Returns the compiler.
  434.      *
  435.      * @return Compiler The compiler
  436.      */
  437.     public function getCompiler()
  438.     {
  439.         if (null === $this->compiler) {
  440.             $this->compiler = new Compiler();
  441.         }
  442.         return $this->compiler;
  443.     }
  444.     /**
  445.      * Sets a service.
  446.      *
  447.      * @param string      $id      The service identifier
  448.      * @param object|null $service The service instance
  449.      *
  450.      * @throws BadMethodCallException When this ContainerBuilder is compiled
  451.      */
  452.     public function set($id$service)
  453.     {
  454.         $id $this->normalizeId($id);
  455.         if ($this->isCompiled() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) {
  456.             // setting a synthetic service on a compiled container is alright
  457.             throw new BadMethodCallException(sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a compiled container is not allowed.'$id));
  458.         }
  459.         unset($this->definitions[$id], $this->aliasDefinitions[$id], $this->removedIds[$id]);
  460.         parent::set($id$service);
  461.     }
  462.     /**
  463.      * Removes a service definition.
  464.      *
  465.      * @param string $id The service identifier
  466.      */
  467.     public function removeDefinition($id)
  468.     {
  469.         if (isset($this->definitions[$id $this->normalizeId($id)])) {
  470.             unset($this->definitions[$id]);
  471.             $this->removedIds[$id] = true;
  472.         }
  473.     }
  474.     /**
  475.      * Returns true if the given service is defined.
  476.      *
  477.      * @param string $id The service identifier
  478.      *
  479.      * @return bool true if the service is defined, false otherwise
  480.      */
  481.     public function has($id)
  482.     {
  483.         $id $this->normalizeId($id);
  484.         return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || parent::has($id);
  485.     }
  486.     /**
  487.      * Gets a service.
  488.      *
  489.      * @param string $id              The service identifier
  490.      * @param int    $invalidBehavior The behavior when the service does not exist
  491.      *
  492.      * @return object|null The associated service
  493.      *
  494.      * @throws InvalidArgumentException          when no definitions are available
  495.      * @throws ServiceCircularReferenceException When a circular reference is detected
  496.      * @throws ServiceNotFoundException          When the service is not defined
  497.      * @throws \Exception
  498.      *
  499.      * @see Reference
  500.      */
  501.     public function get($id$invalidBehavior ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
  502.     {
  503.         if ($this->isCompiled() && isset($this->removedIds[$id $this->normalizeId($id)])) {
  504.             @trigger_error(sprintf('Fetching the "%s" private service or alias is deprecated since Symfony 3.4 and will fail in 4.0. Make it public instead.'$id), E_USER_DEPRECATED);
  505.         }
  506.         return $this->doGet($id$invalidBehavior);
  507.     }
  508.     private function doGet($id$invalidBehavior ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices null$isConstructorArgument false)
  509.     {
  510.         $id $this->normalizeId($id);
  511.         if (isset($inlineServices[$id])) {
  512.             return $inlineServices[$id];
  513.         }
  514.         if (null === $inlineServices) {
  515.             $isConstructorArgument true;
  516.             $inlineServices = [];
  517.         }
  518.         try {
  519.             if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior) {
  520.                 return parent::get($id$invalidBehavior);
  521.             }
  522.             if ($service parent::get($idContainerInterface::NULL_ON_INVALID_REFERENCE)) {
  523.                 return $service;
  524.             }
  525.         } catch (ServiceCircularReferenceException $e) {
  526.             if ($isConstructorArgument) {
  527.                 throw $e;
  528.             }
  529.         }
  530.         if (!isset($this->definitions[$id]) && isset($this->aliasDefinitions[$id])) {
  531.             return $this->doGet((string) $this->aliasDefinitions[$id], $invalidBehavior$inlineServices$isConstructorArgument);
  532.         }
  533.         try {
  534.             $definition $this->getDefinition($id);
  535.         } catch (ServiceNotFoundException $e) {
  536.             if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
  537.                 return null;
  538.             }
  539.             throw $e;
  540.         }
  541.         if ($isConstructorArgument) {
  542.             $this->loading[$id] = true;
  543.         }
  544.         try {
  545.             return $this->createService($definition$inlineServices$isConstructorArgument$id);
  546.         } finally {
  547.             if ($isConstructorArgument) {
  548.                 unset($this->loading[$id]);
  549.             }
  550.         }
  551.     }
  552.     /**
  553.      * Merges a ContainerBuilder with the current ContainerBuilder configuration.
  554.      *
  555.      * Service definitions overrides the current defined ones.
  556.      *
  557.      * But for parameters, they are overridden by the current ones. It allows
  558.      * the parameters passed to the container constructor to have precedence
  559.      * over the loaded ones.
  560.      *
  561.      *     $container = new ContainerBuilder(new ParameterBag(['foo' => 'bar']));
  562.      *     $loader = new LoaderXXX($container);
  563.      *     $loader->load('resource_name');
  564.      *     $container->register('foo', 'stdClass');
  565.      *
  566.      * In the above example, even if the loaded resource defines a foo
  567.      * parameter, the value will still be 'bar' as defined in the ContainerBuilder
  568.      * constructor.
  569.      *
  570.      * @throws BadMethodCallException When this ContainerBuilder is compiled
  571.      */
  572.     public function merge(self $container)
  573.     {
  574.         if ($this->isCompiled()) {
  575.             throw new BadMethodCallException('Cannot merge on a compiled container.');
  576.         }
  577.         $this->addDefinitions($container->getDefinitions());
  578.         $this->addAliases($container->getAliases());
  579.         $this->getParameterBag()->add($container->getParameterBag()->all());
  580.         if ($this->trackResources) {
  581.             foreach ($container->getResources() as $resource) {
  582.                 $this->addResource($resource);
  583.             }
  584.         }
  585.         foreach ($this->extensions as $name => $extension) {
  586.             if (!isset($this->extensionConfigs[$name])) {
  587.                 $this->extensionConfigs[$name] = [];
  588.             }
  589.             $this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
  590.         }
  591.         if ($this->getParameterBag() instanceof EnvPlaceholderParameterBag && $container->getParameterBag() instanceof EnvPlaceholderParameterBag) {
  592.             $envPlaceholders $container->getParameterBag()->getEnvPlaceholders();
  593.             $this->getParameterBag()->mergeEnvPlaceholders($container->getParameterBag());
  594.         } else {
  595.             $envPlaceholders = [];
  596.         }
  597.         foreach ($container->envCounters as $env => $count) {
  598.             if (!$count && !isset($envPlaceholders[$env])) {
  599.                 continue;
  600.             }
  601.             if (!isset($this->envCounters[$env])) {
  602.                 $this->envCounters[$env] = $count;
  603.             } else {
  604.                 $this->envCounters[$env] += $count;
  605.             }
  606.         }
  607.         foreach ($container->getAutoconfiguredInstanceof() as $interface => $childDefinition) {
  608.             if (isset($this->autoconfiguredInstanceof[$interface])) {
  609.                 throw new InvalidArgumentException(sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.'$interface));
  610.             }
  611.             $this->autoconfiguredInstanceof[$interface] = $childDefinition;
  612.         }
  613.     }
  614.     /**
  615.      * Returns the configuration array for the given extension.
  616.      *
  617.      * @param string $name The name of the extension
  618.      *
  619.      * @return array An array of configuration
  620.      */
  621.     public function getExtensionConfig($name)
  622.     {
  623.         if (!isset($this->extensionConfigs[$name])) {
  624.             $this->extensionConfigs[$name] = [];
  625.         }
  626.         return $this->extensionConfigs[$name];
  627.     }
  628.     /**
  629.      * Prepends a config array to the configs of the given extension.
  630.      *
  631.      * @param string $name   The name of the extension
  632.      * @param array  $config The config to set
  633.      */
  634.     public function prependExtensionConfig($name, array $config)
  635.     {
  636.         if (!isset($this->extensionConfigs[$name])) {
  637.             $this->extensionConfigs[$name] = [];
  638.         }
  639.         array_unshift($this->extensionConfigs[$name], $config);
  640.     }
  641.     /**
  642.      * Compiles the container.
  643.      *
  644.      * This method passes the container to compiler
  645.      * passes whose job is to manipulate and optimize
  646.      * the container.
  647.      *
  648.      * The main compiler passes roughly do four things:
  649.      *
  650.      *  * The extension configurations are merged;
  651.      *  * Parameter values are resolved;
  652.      *  * The parameter bag is frozen;
  653.      *  * Extension loading is disabled.
  654.      *
  655.      * @param bool $resolveEnvPlaceholders Whether %env()% parameters should be resolved using the current
  656.      *                                     env vars or be replaced by uniquely identifiable placeholders.
  657.      *                                     Set to "true" when you want to use the current ContainerBuilder
  658.      *                                     directly, keep to "false" when the container is dumped instead.
  659.      */
  660.     public function compile(/*$resolveEnvPlaceholders = false*/)
  661.     {
  662.         if (<= \func_num_args()) {
  663.             $resolveEnvPlaceholders func_get_arg(0);
  664.         } else {
  665.             if (__CLASS__ !== static::class) {
  666.                 $r = new \ReflectionMethod($this__FUNCTION__);
  667.                 if (__CLASS__ !== $r->getDeclaringClass()->getName() && ($r->getNumberOfParameters() || 'resolveEnvPlaceholders' !== $r->getParameters()[0]->name)) {
  668.                     @trigger_error(sprintf('The %s::compile() method expects a first "$resolveEnvPlaceholders" argument since Symfony 3.3. It will be made mandatory in 4.0.', static::class), E_USER_DEPRECATED);
  669.                 }
  670.             }
  671.             $resolveEnvPlaceholders false;
  672.         }
  673.         $compiler $this->getCompiler();
  674.         if ($this->trackResources) {
  675.             foreach ($compiler->getPassConfig()->getPasses() as $pass) {
  676.                 $this->addObjectResource($pass);
  677.             }
  678.         }
  679.         $bag $this->getParameterBag();
  680.         if ($resolveEnvPlaceholders && $bag instanceof EnvPlaceholderParameterBag) {
  681.             $compiler->addPass(new ResolveEnvPlaceholdersPass(), PassConfig::TYPE_AFTER_REMOVING, -1000);
  682.         }
  683.         $compiler->compile($this);
  684.         foreach ($this->definitions as $id => $definition) {
  685.             if ($this->trackResources && $definition->isLazy()) {
  686.                 $this->getReflectionClass($definition->getClass());
  687.             }
  688.         }
  689.         $this->extensionConfigs = [];
  690.         if ($bag instanceof EnvPlaceholderParameterBag) {
  691.             if ($resolveEnvPlaceholders) {
  692.                 $this->parameterBag = new ParameterBag($this->resolveEnvPlaceholders($bag->all(), true));
  693.             }
  694.             $this->envPlaceholders $bag->getEnvPlaceholders();
  695.         }
  696.         parent::compile();
  697.         foreach ($this->definitions $this->aliasDefinitions as $id => $definition) {
  698.             if (!$definition->isPublic() || $definition->isPrivate()) {
  699.                 $this->removedIds[$id] = true;
  700.             }
  701.         }
  702.     }
  703.     /**
  704.      * {@inheritdoc}
  705.      */
  706.     public function getServiceIds()
  707.     {
  708.         return array_map('strval'array_unique(array_merge(array_keys($this->getDefinitions()), array_keys($this->aliasDefinitions), parent::getServiceIds())));
  709.     }
  710.     /**
  711.      * Gets removed service or alias ids.
  712.      *
  713.      * @return array
  714.      */
  715.     public function getRemovedIds()
  716.     {
  717.         return $this->removedIds;
  718.     }
  719.     /**
  720.      * Adds the service aliases.
  721.      */
  722.     public function addAliases(array $aliases)
  723.     {
  724.         foreach ($aliases as $alias => $id) {
  725.             $this->setAlias($alias$id);
  726.         }
  727.     }
  728.     /**
  729.      * Sets the service aliases.
  730.      */
  731.     public function setAliases(array $aliases)
  732.     {
  733.         $this->aliasDefinitions = [];
  734.         $this->addAliases($aliases);
  735.     }
  736.     /**
  737.      * Sets an alias for an existing service.
  738.      *
  739.      * @param string       $alias The alias to create
  740.      * @param string|Alias $id    The service to alias
  741.      *
  742.      * @return Alias
  743.      *
  744.      * @throws InvalidArgumentException if the id is not a string or an Alias
  745.      * @throws InvalidArgumentException if the alias is for itself
  746.      */
  747.     public function setAlias($alias$id)
  748.     {
  749.         $alias $this->normalizeId($alias);
  750.         if ('' === $alias || '\\' === substr($alias, -1) || \strlen($alias) !== strcspn($alias"\0\r\n'")) {
  751.             throw new InvalidArgumentException(sprintf('Invalid alias id: "%s"'$alias));
  752.         }
  753.         if (\is_string($id)) {
  754.             $id = new Alias($this->normalizeId($id));
  755.         } elseif (!$id instanceof Alias) {
  756.             throw new InvalidArgumentException('$id must be a string, or an Alias object.');
  757.         }
  758.         if ($alias === (string) $id) {
  759.             throw new InvalidArgumentException(sprintf('An alias can not reference itself, got a circular reference on "%s".'$alias));
  760.         }
  761.         unset($this->definitions[$alias], $this->removedIds[$alias]);
  762.         return $this->aliasDefinitions[$alias] = $id;
  763.     }
  764.     /**
  765.      * Removes an alias.
  766.      *
  767.      * @param string $alias The alias to remove
  768.      */
  769.     public function removeAlias($alias)
  770.     {
  771.         if (isset($this->aliasDefinitions[$alias $this->normalizeId($alias)])) {
  772.             unset($this->aliasDefinitions[$alias]);
  773.             $this->removedIds[$alias] = true;
  774.         }
  775.     }
  776.     /**
  777.      * Returns true if an alias exists under the given identifier.
  778.      *
  779.      * @param string $id The service identifier
  780.      *
  781.      * @return bool true if the alias exists, false otherwise
  782.      */
  783.     public function hasAlias($id)
  784.     {
  785.         return isset($this->aliasDefinitions[$this->normalizeId($id)]);
  786.     }
  787.     /**
  788.      * Gets all defined aliases.
  789.      *
  790.      * @return Alias[] An array of aliases
  791.      */
  792.     public function getAliases()
  793.     {
  794.         return $this->aliasDefinitions;
  795.     }
  796.     /**
  797.      * Gets an alias.
  798.      *
  799.      * @param string $id The service identifier
  800.      *
  801.      * @return Alias An Alias instance
  802.      *
  803.      * @throws InvalidArgumentException if the alias does not exist
  804.      */
  805.     public function getAlias($id)
  806.     {
  807.         $id $this->normalizeId($id);
  808.         if (!isset($this->aliasDefinitions[$id])) {
  809.             throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.'$id));
  810.         }
  811.         return $this->aliasDefinitions[$id];
  812.     }
  813.     /**
  814.      * Registers a service definition.
  815.      *
  816.      * This methods allows for simple registration of service definition
  817.      * with a fluid interface.
  818.      *
  819.      * @param string      $id    The service identifier
  820.      * @param string|null $class The service class
  821.      *
  822.      * @return Definition A Definition instance
  823.      */
  824.     public function register($id$class null)
  825.     {
  826.         return $this->setDefinition($id, new Definition($class));
  827.     }
  828.     /**
  829.      * Registers an autowired service definition.
  830.      *
  831.      * This method implements a shortcut for using setDefinition() with
  832.      * an autowired definition.
  833.      *
  834.      * @param string      $id    The service identifier
  835.      * @param string|null $class The service class
  836.      *
  837.      * @return Definition The created definition
  838.      */
  839.     public function autowire($id$class null)
  840.     {
  841.         return $this->setDefinition($id, (new Definition($class))->setAutowired(true));
  842.     }
  843.     /**
  844.      * Adds the service definitions.
  845.      *
  846.      * @param Definition[] $definitions An array of service definitions
  847.      */
  848.     public function addDefinitions(array $definitions)
  849.     {
  850.         foreach ($definitions as $id => $definition) {
  851.             $this->setDefinition($id$definition);
  852.         }
  853.     }
  854.     /**
  855.      * Sets the service definitions.
  856.      *
  857.      * @param Definition[] $definitions An array of service definitions
  858.      */
  859.     public function setDefinitions(array $definitions)
  860.     {
  861.         $this->definitions = [];
  862.         $this->addDefinitions($definitions);
  863.     }
  864.     /**
  865.      * Gets all service definitions.
  866.      *
  867.      * @return Definition[] An array of Definition instances
  868.      */
  869.     public function getDefinitions()
  870.     {
  871.         return $this->definitions;
  872.     }
  873.     /**
  874.      * Sets a service definition.
  875.      *
  876.      * @param string     $id         The service identifier
  877.      * @param Definition $definition A Definition instance
  878.      *
  879.      * @return Definition the service definition
  880.      *
  881.      * @throws BadMethodCallException When this ContainerBuilder is compiled
  882.      */
  883.     public function setDefinition($idDefinition $definition)
  884.     {
  885.         if ($this->isCompiled()) {
  886.             throw new BadMethodCallException('Adding definition to a compiled container is not allowed');
  887.         }
  888.         $id $this->normalizeId($id);
  889.         if ('' === $id || '\\' === substr($id, -1) || \strlen($id) !== strcspn($id"\0\r\n'")) {
  890.             throw new InvalidArgumentException(sprintf('Invalid service id: "%s"'$id));
  891.         }
  892.         unset($this->aliasDefinitions[$id], $this->removedIds[$id]);
  893.         return $this->definitions[$id] = $definition;
  894.     }
  895.     /**
  896.      * Returns true if a service definition exists under the given identifier.
  897.      *
  898.      * @param string $id The service identifier
  899.      *
  900.      * @return bool true if the service definition exists, false otherwise
  901.      */
  902.     public function hasDefinition($id)
  903.     {
  904.         return isset($this->definitions[$this->normalizeId($id)]);
  905.     }
  906.     /**
  907.      * Gets a service definition.
  908.      *
  909.      * @param string $id The service identifier
  910.      *
  911.      * @return Definition A Definition instance
  912.      *
  913.      * @throws ServiceNotFoundException if the service definition does not exist
  914.      */
  915.     public function getDefinition($id)
  916.     {
  917.         $id $this->normalizeId($id);
  918.         if (!isset($this->definitions[$id])) {
  919.             throw new ServiceNotFoundException($id);
  920.         }
  921.         return $this->definitions[$id];
  922.     }
  923.     /**
  924.      * Gets a service definition by id or alias.
  925.      *
  926.      * The method "unaliases" recursively to return a Definition instance.
  927.      *
  928.      * @param string $id The service identifier or alias
  929.      *
  930.      * @return Definition A Definition instance
  931.      *
  932.      * @throws ServiceNotFoundException if the service definition does not exist
  933.      */
  934.     public function findDefinition($id)
  935.     {
  936.         $id $this->normalizeId($id);
  937.         $seen = [];
  938.         while (isset($this->aliasDefinitions[$id])) {
  939.             $id = (string) $this->aliasDefinitions[$id];
  940.             if (isset($seen[$id])) {
  941.                 $seen array_values($seen);
  942.                 $seen = \array_slice($seenarray_search($id$seen));
  943.                 $seen[] = $id;
  944.                 throw new ServiceCircularReferenceException($id$seen);
  945.             }
  946.             $seen[$id] = $id;
  947.         }
  948.         return $this->getDefinition($id);
  949.     }
  950.     /**
  951.      * Creates a service for a service definition.
  952.      *
  953.      * @param Definition $definition A service definition instance
  954.      * @param string     $id         The service identifier
  955.      * @param bool       $tryProxy   Whether to try proxying the service with a lazy proxy
  956.      *
  957.      * @return mixed The service described by the service definition
  958.      *
  959.      * @throws RuntimeException         When the factory definition is incomplete
  960.      * @throws RuntimeException         When the service is a synthetic service
  961.      * @throws InvalidArgumentException When configure callable is not callable
  962.      */
  963.     private function createService(Definition $definition, array &$inlineServices$isConstructorArgument false$id null$tryProxy true)
  964.     {
  965.         if (null === $id && isset($inlineServices[$h spl_object_hash($definition)])) {
  966.             return $inlineServices[$h];
  967.         }
  968.         if ($definition instanceof ChildDefinition) {
  969.             throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.'$id));
  970.         }
  971.         if ($definition->isSynthetic()) {
  972.             throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.'$id));
  973.         }
  974.         if ($definition->isDeprecated()) {
  975.             @trigger_error($definition->getDeprecationMessage($id), E_USER_DEPRECATED);
  976.         }
  977.         if ($tryProxy && $definition->isLazy() && !$tryProxy = !($proxy $this->proxyInstantiator) || $proxy instanceof RealServiceInstantiator) {
  978.             $proxy $proxy->instantiateProxy(
  979.                 $this,
  980.                 $definition,
  981.                 $id, function () use ($definition, &$inlineServices$id) {
  982.                     return $this->createService($definition$inlineServicestrue$idfalse);
  983.                 }
  984.             );
  985.             $this->shareService($definition$proxy$id$inlineServices);
  986.             return $proxy;
  987.         }
  988.         $parameterBag $this->getParameterBag();
  989.         if (null !== $definition->getFile()) {
  990.             require_once $parameterBag->resolveValue($definition->getFile());
  991.         }
  992.         $arguments $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlineServices$isConstructorArgument);
  993.         if (null !== $factory $definition->getFactory()) {
  994.             if (\is_array($factory)) {
  995.                 $factory = [$this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlineServices$isConstructorArgument), $factory[1]];
  996.             } elseif (!\is_string($factory)) {
  997.                 throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory'$id));
  998.             }
  999.         }
  1000.         if (null !== $id && $definition->isShared() && isset($this->services[$id]) && ($tryProxy || !$definition->isLazy())) {
  1001.             return $this->services[$id];
  1002.         }
  1003.         if (null !== $factory) {
  1004.             $service = \call_user_func_array($factory$arguments);
  1005.             if (!$definition->isDeprecated() && \is_array($factory) && \is_string($factory[0])) {
  1006.                 $r = new \ReflectionClass($factory[0]);
  1007.                 if (strpos($r->getDocComment(), "\n * @deprecated ")) {
  1008.                     @trigger_error(sprintf('The "%s" service relies on the deprecated "%s" factory class. It should either be deprecated or its factory upgraded.'$id$r->name), E_USER_DEPRECATED);
  1009.                 }
  1010.             }
  1011.         } else {
  1012.             $r = new \ReflectionClass($class $parameterBag->resolveValue($definition->getClass()));
  1013.             $service null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
  1014.             // don't trigger deprecations for internal uses
  1015.             // @deprecated since version 3.3, to be removed in 4.0 along with the deprecated class
  1016.             $deprecationWhitelist = ['event_dispatcher' => ContainerAwareEventDispatcher::class];
  1017.             if (!$definition->isDeprecated() && strpos($r->getDocComment(), "\n * @deprecated ") && (!isset($deprecationWhitelist[$id]) || $deprecationWhitelist[$id] !== $class)) {
  1018.                 @trigger_error(sprintf('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.'$id$r->name), E_USER_DEPRECATED);
  1019.             }
  1020.         }
  1021.         if ($tryProxy || !$definition->isLazy()) {
  1022.             // share only if proxying failed, or if not a proxy
  1023.             $this->shareService($definition$service$id$inlineServices);
  1024.         }
  1025.         $properties $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlineServices);
  1026.         foreach ($properties as $name => $value) {
  1027.             $service->$name $value;
  1028.         }
  1029.         foreach ($definition->getMethodCalls() as $call) {
  1030.             $this->callMethod($service$call$inlineServices);
  1031.         }
  1032.         if ($callable $definition->getConfigurator()) {
  1033.             if (\is_array($callable)) {
  1034.                 $callable[0] = $parameterBag->resolveValue($callable[0]);
  1035.                 if ($callable[0] instanceof Reference) {
  1036.                     $callable[0] = $this->doGet((string) $callable[0], $callable[0]->getInvalidBehavior(), $inlineServices);
  1037.                 } elseif ($callable[0] instanceof Definition) {
  1038.                     $callable[0] = $this->createService($callable[0], $inlineServices);
  1039.                 }
  1040.             }
  1041.             if (!\is_callable($callable)) {
  1042.                 throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', \get_class($service)));
  1043.             }
  1044.             \call_user_func($callable$service);
  1045.         }
  1046.         return $service;
  1047.     }
  1048.     /**
  1049.      * Replaces service references by the real service instance and evaluates expressions.
  1050.      *
  1051.      * @param mixed $value A value
  1052.      *
  1053.      * @return mixed The same value with all service references replaced by
  1054.      *               the real service instances and all expressions evaluated
  1055.      */
  1056.     public function resolveServices($value)
  1057.     {
  1058.         return $this->doResolveServices($value);
  1059.     }
  1060.     private function doResolveServices($value, array &$inlineServices = [], $isConstructorArgument false)
  1061.     {
  1062.         if (\is_array($value)) {
  1063.             foreach ($value as $k => $v) {
  1064.                 $value[$k] = $this->doResolveServices($v$inlineServices$isConstructorArgument);
  1065.             }
  1066.         } elseif ($value instanceof ServiceClosureArgument) {
  1067.             $reference $value->getValues()[0];
  1068.             $value = function () use ($reference) {
  1069.                 return $this->resolveServices($reference);
  1070.             };
  1071.         } elseif ($value instanceof IteratorArgument) {
  1072.             $value = new RewindableGenerator(function () use ($value) {
  1073.                 foreach ($value->getValues() as $k => $v) {
  1074.                     foreach (self::getServiceConditionals($v) as $s) {
  1075.                         if (!$this->has($s)) {
  1076.                             continue 2;
  1077.                         }
  1078.                     }
  1079.                     foreach (self::getInitializedConditionals($v) as $s) {
  1080.                         if (!$this->doGet($sContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
  1081.                             continue 2;
  1082.                         }
  1083.                     }
  1084.                     yield $k => $this->resolveServices($v);
  1085.                 }
  1086.             }, function () use ($value) {
  1087.                 $count 0;
  1088.                 foreach ($value->getValues() as $v) {
  1089.                     foreach (self::getServiceConditionals($v) as $s) {
  1090.                         if (!$this->has($s)) {
  1091.                             continue 2;
  1092.                         }
  1093.                     }
  1094.                     foreach (self::getInitializedConditionals($v) as $s) {
  1095.                         if (!$this->doGet($sContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
  1096.                             continue 2;
  1097.                         }
  1098.                     }
  1099.                     ++$count;
  1100.                 }
  1101.                 return $count;
  1102.             });
  1103.         } elseif ($value instanceof Reference) {
  1104.             $value $this->doGet((string) $value$value->getInvalidBehavior(), $inlineServices$isConstructorArgument);
  1105.         } elseif ($value instanceof Definition) {
  1106.             $value $this->createService($value$inlineServices$isConstructorArgument);
  1107.         } elseif ($value instanceof Parameter) {
  1108.             $value $this->getParameter((string) $value);
  1109.         } elseif ($value instanceof Expression) {
  1110.             $value $this->getExpressionLanguage()->evaluate($value, ['container' => $this]);
  1111.         }
  1112.         return $value;
  1113.     }
  1114.     /**
  1115.      * Returns service ids for a given tag.
  1116.      *
  1117.      * Example:
  1118.      *
  1119.      *     $container->register('foo')->addTag('my.tag', ['hello' => 'world']);
  1120.      *
  1121.      *     $serviceIds = $container->findTaggedServiceIds('my.tag');
  1122.      *     foreach ($serviceIds as $serviceId => $tags) {
  1123.      *         foreach ($tags as $tag) {
  1124.      *             echo $tag['hello'];
  1125.      *         }
  1126.      *     }
  1127.      *
  1128.      * @param string $name
  1129.      * @param bool   $throwOnAbstract
  1130.      *
  1131.      * @return array An array of tags with the tagged service as key, holding a list of attribute arrays
  1132.      */
  1133.     public function findTaggedServiceIds($name$throwOnAbstract false)
  1134.     {
  1135.         $this->usedTags[] = $name;
  1136.         $tags = [];
  1137.         foreach ($this->getDefinitions() as $id => $definition) {
  1138.             if ($definition->hasTag($name)) {
  1139.                 if ($throwOnAbstract && $definition->isAbstract()) {
  1140.                     throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must not be abstract.'$id$name));
  1141.                 }
  1142.                 $tags[$id] = $definition->getTag($name);
  1143.             }
  1144.         }
  1145.         return $tags;
  1146.     }
  1147.     /**
  1148.      * Returns all tags the defined services use.
  1149.      *
  1150.      * @return array An array of tags
  1151.      */
  1152.     public function findTags()
  1153.     {
  1154.         $tags = [];
  1155.         foreach ($this->getDefinitions() as $id => $definition) {
  1156.             $tags array_merge(array_keys($definition->getTags()), $tags);
  1157.         }
  1158.         return array_unique($tags);
  1159.     }
  1160.     /**
  1161.      * Returns all tags not queried by findTaggedServiceIds.
  1162.      *
  1163.      * @return string[] An array of tags
  1164.      */
  1165.     public function findUnusedTags()
  1166.     {
  1167.         return array_values(array_diff($this->findTags(), $this->usedTags));
  1168.     }
  1169.     public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
  1170.     {
  1171.         $this->expressionLanguageProviders[] = $provider;
  1172.     }
  1173.     /**
  1174.      * @return ExpressionFunctionProviderInterface[]
  1175.      */
  1176.     public function getExpressionLanguageProviders()
  1177.     {
  1178.         return $this->expressionLanguageProviders;
  1179.     }
  1180.     /**
  1181.      * Returns a ChildDefinition that will be used for autoconfiguring the interface/class.
  1182.      *
  1183.      * @param string $interface The class or interface to match
  1184.      *
  1185.      * @return ChildDefinition
  1186.      */
  1187.     public function registerForAutoconfiguration($interface)
  1188.     {
  1189.         if (!isset($this->autoconfiguredInstanceof[$interface])) {
  1190.             $this->autoconfiguredInstanceof[$interface] = new ChildDefinition('');
  1191.         }
  1192.         return $this->autoconfiguredInstanceof[$interface];
  1193.     }
  1194.     /**
  1195.      * Returns an array of ChildDefinition[] keyed by interface.
  1196.      *
  1197.      * @return ChildDefinition[]
  1198.      */
  1199.     public function getAutoconfiguredInstanceof()
  1200.     {
  1201.         return $this->autoconfiguredInstanceof;
  1202.     }
  1203.     /**
  1204.      * Resolves env parameter placeholders in a string or an array.
  1205.      *
  1206.      * @param mixed            $value     The value to resolve
  1207.      * @param string|true|null $format    A sprintf() format returning the replacement for each env var name or
  1208.      *                                    null to resolve back to the original "%env(VAR)%" format or
  1209.      *                                    true to resolve to the actual values of the referenced env vars
  1210.      * @param array            &$usedEnvs Env vars found while resolving are added to this array
  1211.      *
  1212.      * @return mixed The value with env parameters resolved if a string or an array is passed
  1213.      */
  1214.     public function resolveEnvPlaceholders($value$format null, array &$usedEnvs null)
  1215.     {
  1216.         if (null === $format) {
  1217.             $format '%%env(%s)%%';
  1218.         }
  1219.         $bag $this->getParameterBag();
  1220.         if (true === $format) {
  1221.             $value $bag->resolveValue($value);
  1222.         }
  1223.         if (\is_array($value)) {
  1224.             $result = [];
  1225.             foreach ($value as $k => $v) {
  1226.                 $result[\is_string($k) ? $this->resolveEnvPlaceholders($k$format$usedEnvs) : $k] = $this->resolveEnvPlaceholders($v$format$usedEnvs);
  1227.             }
  1228.             return $result;
  1229.         }
  1230.         if (!\is_string($value) || 38 > \strlen($value)) {
  1231.             return $value;
  1232.         }
  1233.         $envPlaceholders $bag instanceof EnvPlaceholderParameterBag $bag->getEnvPlaceholders() : $this->envPlaceholders;
  1234.         $completed false;
  1235.         foreach ($envPlaceholders as $env => $placeholders) {
  1236.             foreach ($placeholders as $placeholder) {
  1237.                 if (false !== stripos($value$placeholder)) {
  1238.                     if (true === $format) {
  1239.                         $resolved $bag->escapeValue($this->getEnv($env));
  1240.                     } else {
  1241.                         $resolved sprintf($format$env);
  1242.                     }
  1243.                     if ($placeholder === $value) {
  1244.                         $value $resolved;
  1245.                         $completed true;
  1246.                     } else {
  1247.                         if (!\is_string($resolved) && !is_numeric($resolved)) {
  1248.                             throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "env(%s)" of type %s inside string value "%s".'$env, \gettype($resolved), $this->resolveEnvPlaceholders($value)));
  1249.                         }
  1250.                         $value str_ireplace($placeholder$resolved$value);
  1251.                     }
  1252.                     $usedEnvs[$env] = $env;
  1253.                     $this->envCounters[$env] = isset($this->envCounters[$env]) ? $this->envCounters[$env] : 1;
  1254.                     if ($completed) {
  1255.                         break 2;
  1256.                     }
  1257.                 }
  1258.             }
  1259.         }
  1260.         return $value;
  1261.     }
  1262.     /**
  1263.      * Get statistics about env usage.
  1264.      *
  1265.      * @return int[] The number of time each env vars has been resolved
  1266.      */
  1267.     public function getEnvCounters()
  1268.     {
  1269.         $bag $this->getParameterBag();
  1270.         $envPlaceholders $bag instanceof EnvPlaceholderParameterBag $bag->getEnvPlaceholders() : $this->envPlaceholders;
  1271.         foreach ($envPlaceholders as $env => $placeholders) {
  1272.             if (!isset($this->envCounters[$env])) {
  1273.                 $this->envCounters[$env] = 0;
  1274.             }
  1275.         }
  1276.         return $this->envCounters;
  1277.     }
  1278.     /**
  1279.      * @internal
  1280.      */
  1281.     public function getNormalizedIds()
  1282.     {
  1283.         $normalizedIds = [];
  1284.         foreach ($this->normalizedIds as $k => $v) {
  1285.             if ($v !== (string) $k) {
  1286.                 $normalizedIds[$k] = $v;
  1287.             }
  1288.         }
  1289.         return $normalizedIds;
  1290.     }
  1291.     /**
  1292.      * @final
  1293.      */
  1294.     public function log(CompilerPassInterface $pass$message)
  1295.     {
  1296.         $this->getCompiler()->log($pass$this->resolveEnvPlaceholders($message));
  1297.     }
  1298.     /**
  1299.      * {@inheritdoc}
  1300.      */
  1301.     public function normalizeId($id)
  1302.     {
  1303.         if (!\is_string($id)) {
  1304.             $id = (string) $id;
  1305.         }
  1306.         return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || isset($this->removedIds[$id]) ? $id parent::normalizeId($id);
  1307.     }
  1308.     /**
  1309.      * Gets removed binding ids.
  1310.      *
  1311.      * @return array
  1312.      *
  1313.      * @internal
  1314.      */
  1315.     public function getRemovedBindingIds()
  1316.     {
  1317.         return $this->removedBindingIds;
  1318.     }
  1319.     /**
  1320.      * Removes bindings for a service.
  1321.      *
  1322.      * @param string $id The service identifier
  1323.      *
  1324.      * @internal
  1325.      */
  1326.     public function removeBindings($id)
  1327.     {
  1328.         if ($this->hasDefinition($id)) {
  1329.             foreach ($this->getDefinition($id)->getBindings() as $key => $binding) {
  1330.                 list(, $bindingId) = $binding->getValues();
  1331.                 $this->removedBindingIds[(int) $bindingId] = true;
  1332.             }
  1333.         }
  1334.     }
  1335.     /**
  1336.      * Returns the Service Conditionals.
  1337.      *
  1338.      * @param mixed $value An array of conditionals to return
  1339.      *
  1340.      * @return array An array of Service conditionals
  1341.      *
  1342.      * @internal since version 3.4
  1343.      */
  1344.     public static function getServiceConditionals($value)
  1345.     {
  1346.         $services = [];
  1347.         if (\is_array($value)) {
  1348.             foreach ($value as $v) {
  1349.                 $services array_unique(array_merge($servicesself::getServiceConditionals($v)));
  1350.             }
  1351.         } elseif ($value instanceof Reference && ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) {
  1352.             $services[] = (string) $value;
  1353.         }
  1354.         return $services;
  1355.     }
  1356.     /**
  1357.      * Returns the initialized conditionals.
  1358.      *
  1359.      * @param mixed $value An array of conditionals to return
  1360.      *
  1361.      * @return array An array of uninitialized conditionals
  1362.      *
  1363.      * @internal
  1364.      */
  1365.     public static function getInitializedConditionals($value)
  1366.     {
  1367.         $services = [];
  1368.         if (\is_array($value)) {
  1369.             foreach ($value as $v) {
  1370.                 $services array_unique(array_merge($servicesself::getInitializedConditionals($v)));
  1371.             }
  1372.         } elseif ($value instanceof Reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()) {
  1373.             $services[] = (string) $value;
  1374.         }
  1375.         return $services;
  1376.     }
  1377.     /**
  1378.      * Computes a reasonably unique hash of a value.
  1379.      *
  1380.      * @param mixed $value A serializable value
  1381.      *
  1382.      * @return string
  1383.      */
  1384.     public static function hash($value)
  1385.     {
  1386.         $hash substr(base64_encode(hash('sha256'serialize($value), true)), 07);
  1387.         return str_replace(['/''+'], ['.''_'], strtolower($hash));
  1388.     }
  1389.     /**
  1390.      * {@inheritdoc}
  1391.      */
  1392.     protected function getEnv($name)
  1393.     {
  1394.         $value parent::getEnv($name);
  1395.         $bag $this->getParameterBag();
  1396.         if (!\is_string($value) || !$bag instanceof EnvPlaceholderParameterBag) {
  1397.             return $value;
  1398.         }
  1399.         foreach ($bag->getEnvPlaceholders() as $env => $placeholders) {
  1400.             if (isset($placeholders[$value])) {
  1401.                 $bag = new ParameterBag($bag->all());
  1402.                 return $bag->unescapeValue($bag->get("env($name)"));
  1403.             }
  1404.         }
  1405.         $this->resolving["env($name)"] = true;
  1406.         try {
  1407.             return $bag->unescapeValue($this->resolveEnvPlaceholders($bag->escapeValue($value), true));
  1408.         } finally {
  1409.             unset($this->resolving["env($name)"]);
  1410.         }
  1411.     }
  1412.     private function callMethod($service$call, array &$inlineServices)
  1413.     {
  1414.         foreach (self::getServiceConditionals($call[1]) as $s) {
  1415.             if (!$this->has($s)) {
  1416.                 return;
  1417.             }
  1418.         }
  1419.         foreach (self::getInitializedConditionals($call[1]) as $s) {
  1420.             if (!$this->doGet($sContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE$inlineServices)) {
  1421.                 return;
  1422.             }
  1423.         }
  1424.         \call_user_func_array([$service$call[0]], $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlineServices));
  1425.     }
  1426.     /**
  1427.      * Shares a given service in the container.
  1428.      *
  1429.      * @param mixed       $service
  1430.      * @param string|null $id
  1431.      */
  1432.     private function shareService(Definition $definition$service$id, array &$inlineServices)
  1433.     {
  1434.         $inlineServices[null !== $id $id spl_object_hash($definition)] = $service;
  1435.         if (null !== $id && $definition->isShared()) {
  1436.             $this->services[$id] = $service;
  1437.             unset($this->loading[$id]);
  1438.         }
  1439.     }
  1440.     private function getExpressionLanguage()
  1441.     {
  1442.         if (null === $this->expressionLanguage) {
  1443.             if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
  1444.                 throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
  1445.             }
  1446.             $this->expressionLanguage = new ExpressionLanguage(null$this->expressionLanguageProviders);
  1447.         }
  1448.         return $this->expressionLanguage;
  1449.     }
  1450.     private function inVendors($path)
  1451.     {
  1452.         if (null === $this->vendors) {
  1453.             $resource = new ComposerResource();
  1454.             $this->vendors $resource->getVendors();
  1455.             $this->addResource($resource);
  1456.         }
  1457.         $path realpath($path) ?: $path;
  1458.         foreach ($this->vendors as $vendor) {
  1459.             if (=== strpos($path$vendor) && false !== strpbrk(substr($path, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
  1460.                 return true;
  1461.             }
  1462.         }
  1463.         return false;
  1464.     }
  1465. }