Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

ContainerBuilder.php

Zuletzt modifiziert: 02.04.2025, 15:02 - Dateigröße: 55.05 KiB


0001  <?php
0002   
0003  /*
0004   * This file is part of the Symfony package.
0005   *
0006   * (c) Fabien Potencier <fabien@symfony.com>
0007   *
0008   * For the full copyright and license information, please view the LICENSE
0009   * file that was distributed with this source code.
0010   */
0011   
0012  namespace Symfony\Component\DependencyInjection;
0013   
0014  use Psr\Container\ContainerInterface as PsrContainerInterface;
0015  use Symfony\Component\Config\Resource\ClassExistenceResource;
0016  use Symfony\Component\Config\Resource\ComposerResource;
0017  use Symfony\Component\Config\Resource\DirectoryResource;
0018  use Symfony\Component\Config\Resource\FileExistenceResource;
0019  use Symfony\Component\Config\Resource\FileResource;
0020  use Symfony\Component\Config\Resource\GlobResource;
0021  use Symfony\Component\Config\Resource\ReflectionClassResource;
0022  use Symfony\Component\Config\Resource\ResourceInterface;
0023  use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
0024  use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
0025  use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
0026  use Symfony\Component\DependencyInjection\Compiler\Compiler;
0027  use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
0028  use Symfony\Component\DependencyInjection\Compiler\PassConfig;
0029  use Symfony\Component\DependencyInjection\Compiler\ResolveEnvPlaceholdersPass;
0030  use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
0031  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
0032  use Symfony\Component\DependencyInjection\Exception\LogicException;
0033  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
0034  use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
0035  use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
0036  use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
0037  use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
0038  use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
0039  use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
0040  use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
0041  use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
0042  use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
0043  use Symfony\Component\ExpressionLanguage\Expression;
0044  use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
0045   
0046  /**
0047   * ContainerBuilder is a DI container that provides an API to easily describe services.
0048   *
0049   * @author Fabien Potencier <fabien@symfony.com>
0050   */
0051  class ContainerBuilder extends Container implements TaggedContainerInterface
0052  {
0053      /**
0054       * @var ExtensionInterface[]
0055       */
0056      private $extensions = [];
0057   
0058      /**
0059       * @var ExtensionInterface[]
0060       */
0061      private $extensionsByNs = [];
0062   
0063      /**
0064       * @var Definition[]
0065       */
0066      private $definitions = [];
0067   
0068      /**
0069       * @var Alias[]
0070       */
0071      private $aliasDefinitions = [];
0072   
0073      /**
0074       * @var ResourceInterface[]
0075       */
0076      private $resources = [];
0077   
0078      private $extensionConfigs = [];
0079   
0080      /**
0081       * @var Compiler
0082       */
0083      private $compiler;
0084   
0085      private $trackResources;
0086   
0087      /**
0088       * @var InstantiatorInterface|null
0089       */
0090      private $proxyInstantiator;
0091   
0092      /**
0093       * @var ExpressionLanguage|null
0094       */
0095      private $expressionLanguage;
0096   
0097      /**
0098       * @var ExpressionFunctionProviderInterface[]
0099       */
0100      private $expressionLanguageProviders = [];
0101   
0102      /**
0103       * @var string[] with tag names used by findTaggedServiceIds
0104       */
0105      private $usedTags = [];
0106   
0107      /**
0108       * @var string[][] a map of env var names to their placeholders
0109       */
0110      private $envPlaceholders = [];
0111   
0112      /**
0113       * @var int[] a map of env vars to their resolution counter
0114       */
0115      private $envCounters = [];
0116   
0117      /**
0118       * @var string[] the list of vendor directories
0119       */
0120      private $vendors;
0121   
0122      private $autoconfiguredInstanceof = [];
0123   
0124      private $removedIds = [];
0125   
0126      private $removedBindingIds = [];
0127   
0128      private static $internalTypes = [
0129          'int' => true,
0130          'float' => true,
0131          'string' => true,
0132          'bool' => true,
0133          'resource' => true,
0134          'object' => true,
0135          'array' => true,
0136          'null' => true,
0137          'callable' => true,
0138          'iterable' => true,
0139          'mixed' => true,
0140      ];
0141   
0142      public function __construct(ParameterBagInterface $parameterBag = null)
0143      {
0144          parent::__construct($parameterBag);
0145   
0146          $this->trackResources = interface_exists('Symfony\Component\Config\Resource\ResourceInterface');
0147          $this->setDefinition('service_container', (new Definition(ContainerInterface::class))->setSynthetic(true)->setPublic(true));
0148          $this->setAlias(PsrContainerInterface::class, new Alias('service_container', false));
0149          $this->setAlias(ContainerInterface::class, new Alias('service_container', false));
0150      }
0151   
0152      /**
0153       * @var \ReflectionClass[] a list of class reflectors
0154       */
0155      private $classReflectors;
0156   
0157      /**
0158       * Sets the track resources flag.
0159       *
0160       * If you are not using the loaders and therefore don't want
0161       * to depend on the Config component, set this flag to false.
0162       *
0163       * @param bool $track True if you want to track resources, false otherwise
0164       */
0165      public function setResourceTracking($track)
0166      {
0167          $this->trackResources = (bool) $track;
0168      }
0169   
0170      /**
0171       * Checks if resources are tracked.
0172       *
0173       * @return bool true If resources are tracked, false otherwise
0174       */
0175      public function isTrackingResources()
0176      {
0177          return $this->trackResources;
0178      }
0179   
0180      /**
0181       * Sets the instantiator to be used when fetching proxies.
0182       */
0183      public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator)
0184      {
0185          $this->proxyInstantiator = $proxyInstantiator;
0186      }
0187   
0188      public function registerExtension(ExtensionInterface $extension)
0189      {
0190          $this->extensions[$extension->getAlias()] = $extension;
0191   
0192          if (false !== $extension->getNamespace()) {
0193              $this->extensionsByNs[$extension->getNamespace()] = $extension;
0194          }
0195      }
0196   
0197      /**
0198       * Returns an extension by alias or namespace.
0199       *
0200       * @param string $name An alias or a namespace
0201       *
0202       * @return ExtensionInterface An extension instance
0203       *
0204       * @throws LogicException if the extension is not registered
0205       */
0206      public function getExtension($name)
0207      {
0208          if (isset($this->extensions[$name])) {
0209              return $this->extensions[$name];
0210          }
0211   
0212          if (isset($this->extensionsByNs[$name])) {
0213              return $this->extensionsByNs[$name];
0214          }
0215   
0216          throw new LogicException(sprintf('Container extension "%s" is not registered.', $name));
0217      }
0218   
0219      /**
0220       * Returns all registered extensions.
0221       *
0222       * @return ExtensionInterface[] An array of ExtensionInterface
0223       */
0224      public function getExtensions()
0225      {
0226          return $this->extensions;
0227      }
0228   
0229      /**
0230       * Checks if we have an extension.
0231       *
0232       * @param string $name The name of the extension
0233       *
0234       * @return bool If the extension exists
0235       */
0236      public function hasExtension($name)
0237      {
0238          return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]);
0239      }
0240   
0241      /**
0242       * Returns an array of resources loaded to build this configuration.
0243       *
0244       * @return ResourceInterface[] An array of resources
0245       */
0246      public function getResources()
0247      {
0248          return array_values($this->resources);
0249      }
0250   
0251      /**
0252       * @return $this
0253       */
0254      public function addResource(ResourceInterface $resource)
0255      {
0256          if (!$this->trackResources) {
0257              return $this;
0258          }
0259   
0260          if ($resource instanceof GlobResource && $this->inVendors($resource->getPrefix())) {
0261              return $this;
0262          }
0263   
0264          $this->resources[(string) $resource] = $resource;
0265   
0266          return $this;
0267      }
0268   
0269      /**
0270       * Sets the resources for this configuration.
0271       *
0272       * @param ResourceInterface[] $resources An array of resources
0273       *
0274       * @return $this
0275       */
0276      public function setResources(array $resources)
0277      {
0278          if (!$this->trackResources) {
0279              return $this;
0280          }
0281   
0282          $this->resources = $resources;
0283   
0284          return $this;
0285      }
0286   
0287      /**
0288       * Adds the object class hierarchy as resources.
0289       *
0290       * @param object|string $object An object instance or class name
0291       *
0292       * @return $this
0293       */
0294      public function addObjectResource($object)
0295      {
0296          if ($this->trackResources) {
0297              if (\is_object($object)) {
0298                  $object = \get_class($object);
0299              }
0300              if (!isset($this->classReflectors[$object])) {
0301                  $this->classReflectors[$object] = new \ReflectionClass($object);
0302              }
0303              $class = $this->classReflectors[$object];
0304   
0305              foreach ($class->getInterfaceNames() as $name) {
0306                  if (null === $interface = &$this->classReflectors[$name]) {
0307                      $interface = new \ReflectionClass($name);
0308                  }
0309                  $file = $interface->getFileName();
0310                  if (false !== $file && file_exists($file)) {
0311                      $this->fileExists($file);
0312                  }
0313              }
0314              do {
0315                  $file = $class->getFileName();
0316                  if (false !== $file && file_exists($file)) {
0317                      $this->fileExists($file);
0318                  }
0319                  foreach ($class->getTraitNames() as $name) {
0320                      $this->addObjectResource($name);
0321                  }
0322              } while ($class = $class->getParentClass());
0323          }
0324   
0325          return $this;
0326      }
0327   
0328      /**
0329       * Adds the given class hierarchy as resources.
0330       *
0331       * @return $this
0332       *
0333       * @deprecated since version 3.3, to be removed in 4.0. Use addObjectResource() or getReflectionClass() instead.
0334       */
0335      public function addClassResource(\ReflectionClass $class)
0336      {
0337          @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);
0338   
0339          return $this->addObjectResource($class->name);
0340      }
0341   
0342      /**
0343       * Retrieves the requested reflection class and registers it for resource tracking.
0344       *
0345       * @param string $class
0346       * @param bool   $throw
0347       *
0348       * @return \ReflectionClass|null
0349       *
0350       * @throws \ReflectionException when a parent class/interface/trait is not found and $throw is true
0351       *
0352       * @final
0353       */
0354      public function getReflectionClass($class, $throw = true)
0355      {
0356          if (!$class = $this->getParameterBag()->resolveValue($class)) {
0357              return null;
0358          }
0359   
0360          if (isset(self::$internalTypes[$class])) {
0361              return null;
0362          }
0363   
0364          $resource = $classReflector = null;
0365   
0366          try {
0367              if (isset($this->classReflectors[$class])) {
0368                  $classReflector = $this->classReflectors[$class];
0369              } elseif (class_exists(ClassExistenceResource::class)) {
0370                  $resource = new ClassExistenceResource($class, false);
0371                  $classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
0372              } else {
0373                  $classReflector = class_exists($class) ? new \ReflectionClass($class) : false;
0374              }
0375          } catch (\ReflectionException $e) {
0376              if ($throw) {
0377                  throw $e;
0378              }
0379          }
0380   
0381          if ($this->trackResources) {
0382              if (!$classReflector) {
0383                  $this->addResource($resource ?: new ClassExistenceResource($class, false));
0384              } elseif (!$classReflector->isInternal()) {
0385                  $path = $classReflector->getFileName();
0386   
0387                  if (!$this->inVendors($path)) {
0388                      $this->addResource(new ReflectionClassResource($classReflector, $this->vendors));
0389                  }
0390              }
0391              $this->classReflectors[$class] = $classReflector;
0392          }
0393   
0394          return $classReflector ?: null;
0395      }
0396   
0397      /**
0398       * Checks whether the requested file or directory exists and registers the result for resource tracking.
0399       *
0400       * @param string      $path          The file or directory path for which to check the existence
0401       * @param bool|string $trackContents Whether to track contents of the given resource. If a string is passed,
0402       *                                   it will be used as pattern for tracking contents of the requested directory
0403       *
0404       * @return bool
0405       *
0406       * @final
0407       */
0408      public function fileExists($path, $trackContents = true)
0409      {
0410          $exists = file_exists($path);
0411   
0412          if (!$this->trackResources || $this->inVendors($path)) {
0413              return $exists;
0414          }
0415   
0416          if (!$exists) {
0417              $this->addResource(new FileExistenceResource($path));
0418   
0419              return $exists;
0420          }
0421   
0422          if (is_dir($path)) {
0423              if ($trackContents) {
0424                  $this->addResource(new DirectoryResource($path, \is_string($trackContents) ? $trackContents : null));
0425              } else {
0426                  $this->addResource(new GlobResource($path, '/*', false));
0427              }
0428          } elseif ($trackContents) {
0429              $this->addResource(new FileResource($path));
0430          }
0431   
0432          return $exists;
0433      }
0434   
0435      /**
0436       * Loads the configuration for an extension.
0437       *
0438       * @param string $extension The extension alias or namespace
0439       * @param array  $values    An array of values that customizes the extension
0440       *
0441       * @return $this
0442       *
0443       * @throws BadMethodCallException When this ContainerBuilder is compiled
0444       * @throws \LogicException        if the extension is not registered
0445       */
0446      public function loadFromExtension($extension, array $values = null)
0447      {
0448          if ($this->isCompiled()) {
0449              throw new BadMethodCallException('Cannot load from an extension on a compiled container.');
0450          }
0451   
0452          if (\func_num_args() < 2) {
0453              $values = [];
0454          }
0455   
0456          $namespace = $this->getExtension($extension)->getAlias();
0457   
0458          $this->extensionConfigs[$namespace][] = $values;
0459   
0460          return $this;
0461      }
0462   
0463      /**
0464       * Adds a compiler pass.
0465       *
0466       * @param CompilerPassInterface $pass     A compiler pass
0467       * @param string                $type     The type of compiler pass
0468       * @param int                   $priority Used to sort the passes
0469       *
0470       * @return $this
0471       */
0472      public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/)
0473      {
0474          if (\func_num_args() >= 3) {
0475              $priority = func_get_arg(2);
0476          } else {
0477              if (__CLASS__ !== static::class) {
0478                  $r = new \ReflectionMethod($this, __FUNCTION__);
0479                  if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
0480                      @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);
0481                  }
0482              }
0483   
0484              $priority = 0;
0485          }
0486   
0487          $this->getCompiler()->addPass($pass, $type, $priority);
0488   
0489          $this->addObjectResource($pass);
0490   
0491          return $this;
0492      }
0493   
0494      /**
0495       * Returns the compiler pass config which can then be modified.
0496       *
0497       * @return PassConfig The compiler pass config
0498       */
0499      public function getCompilerPassConfig()
0500      {
0501          return $this->getCompiler()->getPassConfig();
0502      }
0503   
0504      /**
0505       * Returns the compiler.
0506       *
0507       * @return Compiler The compiler
0508       */
0509      public function getCompiler()
0510      {
0511          if (null === $this->compiler) {
0512              $this->compiler = new Compiler();
0513          }
0514   
0515          return $this->compiler;
0516      }
0517   
0518      /**
0519       * Sets a service.
0520       *
0521       * @param string      $id      The service identifier
0522       * @param object|null $service The service instance
0523       *
0524       * @throws BadMethodCallException When this ContainerBuilder is compiled
0525       */
0526      public function set($id, $service)
0527      {
0528          $id = $this->normalizeId($id);
0529   
0530          if ($this->isCompiled() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) {
0531              // setting a synthetic service on a compiled container is alright
0532              throw new BadMethodCallException(sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a compiled container is not allowed.', $id));
0533          }
0534   
0535          unset($this->definitions[$id], $this->aliasDefinitions[$id], $this->removedIds[$id]);
0536   
0537          parent::set($id, $service);
0538      }
0539   
0540      /**
0541       * Removes a service definition.
0542       *
0543       * @param string $id The service identifier
0544       */
0545      public function removeDefinition($id)
0546      {
0547          if (isset($this->definitions[$id = $this->normalizeId($id)])) {
0548              unset($this->definitions[$id]);
0549              $this->removedIds[$id] = true;
0550          }
0551      }
0552   
0553      /**
0554       * Returns true if the given service is defined.
0555       *
0556       * @param string $id The service identifier
0557       *
0558       * @return bool true if the service is defined, false otherwise
0559       */
0560      public function has($id)
0561      {
0562          $id = $this->normalizeId($id);
0563   
0564          return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || parent::has($id);
0565      }
0566   
0567      /**
0568       * Gets a service.
0569       *
0570       * @param string $id              The service identifier
0571       * @param int    $invalidBehavior The behavior when the service does not exist
0572       *
0573       * @return object|null The associated service
0574       *
0575       * @throws InvalidArgumentException          when no definitions are available
0576       * @throws ServiceCircularReferenceException When a circular reference is detected
0577       * @throws ServiceNotFoundException          When the service is not defined
0578       * @throws \Exception
0579       *
0580       * @see Reference
0581       */
0582      public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
0583      {
0584          if ($this->isCompiled() && isset($this->removedIds[$id = $this->normalizeId($id)])) {
0585              @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);
0586          }
0587   
0588          return $this->doGet($id, $invalidBehavior);
0589      }
0590   
0591      private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices = null, $isConstructorArgument = false)
0592      {
0593          $id = $this->normalizeId($id);
0594   
0595          if (isset($inlineServices[$id])) {
0596              return $inlineServices[$id];
0597          }
0598          if (null === $inlineServices) {
0599              $isConstructorArgument = true;
0600              $inlineServices = [];
0601          }
0602          try {
0603              if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior) {
0604                  return parent::get($id, $invalidBehavior);
0605              }
0606              if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
0607                  return $service;
0608              }
0609          } catch (ServiceCircularReferenceException $e) {
0610              if ($isConstructorArgument) {
0611                  throw $e;
0612              }
0613          }
0614   
0615          if (!isset($this->definitions[$id]) && isset($this->aliasDefinitions[$id])) {
0616              return $this->doGet((string) $this->aliasDefinitions[$id], $invalidBehavior, $inlineServices, $isConstructorArgument);
0617          }
0618   
0619          try {
0620              $definition = $this->getDefinition($id);
0621          } catch (ServiceNotFoundException $e) {
0622              if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
0623                  return null;
0624              }
0625   
0626              throw $e;
0627          }
0628   
0629          if ($isConstructorArgument) {
0630              $this->loading[$id] = true;
0631          }
0632   
0633          try {
0634              return $this->createService($definition, $inlineServices, $isConstructorArgument, $id);
0635          } finally {
0636              if ($isConstructorArgument) {
0637                  unset($this->loading[$id]);
0638              }
0639          }
0640      }
0641   
0642      /**
0643       * Merges a ContainerBuilder with the current ContainerBuilder configuration.
0644       *
0645       * Service definitions overrides the current defined ones.
0646       *
0647       * But for parameters, they are overridden by the current ones. It allows
0648       * the parameters passed to the container constructor to have precedence
0649       * over the loaded ones.
0650       *
0651       *     $container = new ContainerBuilder(new ParameterBag(['foo' => 'bar']));
0652       *     $loader = new LoaderXXX($container);
0653       *     $loader->load('resource_name');
0654       *     $container->register('foo', 'stdClass');
0655       *
0656       * In the above example, even if the loaded resource defines a foo
0657       * parameter, the value will still be 'bar' as defined in the ContainerBuilder
0658       * constructor.
0659       *
0660       * @throws BadMethodCallException When this ContainerBuilder is compiled
0661       */
0662      public function merge(self $container)
0663      {
0664          if ($this->isCompiled()) {
0665              throw new BadMethodCallException('Cannot merge on a compiled container.');
0666          }
0667   
0668          $this->addDefinitions($container->getDefinitions());
0669          $this->addAliases($container->getAliases());
0670          $this->getParameterBag()->add($container->getParameterBag()->all());
0671   
0672          if ($this->trackResources) {
0673              foreach ($container->getResources() as $resource) {
0674                  $this->addResource($resource);
0675              }
0676          }
0677   
0678          foreach ($this->extensions as $name => $extension) {
0679              if (!isset($this->extensionConfigs[$name])) {
0680                  $this->extensionConfigs[$name] = [];
0681              }
0682   
0683              $this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
0684          }
0685   
0686          if ($this->getParameterBag() instanceof EnvPlaceholderParameterBag && $container->getParameterBag() instanceof EnvPlaceholderParameterBag) {
0687              $envPlaceholders = $container->getParameterBag()->getEnvPlaceholders();
0688              $this->getParameterBag()->mergeEnvPlaceholders($container->getParameterBag());
0689          } else {
0690              $envPlaceholders = [];
0691          }
0692   
0693          foreach ($container->envCounters as $env => $count) {
0694              if (!$count && !isset($envPlaceholders[$env])) {
0695                  continue;
0696              }
0697              if (!isset($this->envCounters[$env])) {
0698                  $this->envCounters[$env] = $count;
0699              } else {
0700                  $this->envCounters[$env] += $count;
0701              }
0702          }
0703   
0704          foreach ($container->getAutoconfiguredInstanceof() as $interface => $childDefinition) {
0705              if (isset($this->autoconfiguredInstanceof[$interface])) {
0706                  throw new InvalidArgumentException(sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.', $interface));
0707              }
0708   
0709              $this->autoconfiguredInstanceof[$interface] = $childDefinition;
0710          }
0711      }
0712   
0713      /**
0714       * Returns the configuration array for the given extension.
0715       *
0716       * @param string $name The name of the extension
0717       *
0718       * @return array An array of configuration
0719       */
0720      public function getExtensionConfig($name)
0721      {
0722          if (!isset($this->extensionConfigs[$name])) {
0723              $this->extensionConfigs[$name] = [];
0724          }
0725   
0726          return $this->extensionConfigs[$name];
0727      }
0728   
0729      /**
0730       * Prepends a config array to the configs of the given extension.
0731       *
0732       * @param string $name   The name of the extension
0733       * @param array  $config The config to set
0734       */
0735      public function prependExtensionConfig($name, array $config)
0736      {
0737          if (!isset($this->extensionConfigs[$name])) {
0738              $this->extensionConfigs[$name] = [];
0739          }
0740   
0741          array_unshift($this->extensionConfigs[$name], $config);
0742      }
0743   
0744      /**
0745       * Compiles the container.
0746       *
0747       * This method passes the container to compiler
0748       * passes whose job is to manipulate and optimize
0749       * the container.
0750       *
0751       * The main compiler passes roughly do four things:
0752       *
0753       *  * The extension configurations are merged;
0754       *  * Parameter values are resolved;
0755       *  * The parameter bag is frozen;
0756       *  * Extension loading is disabled.
0757       *
0758       * @param bool $resolveEnvPlaceholders Whether %env()% parameters should be resolved using the current
0759       *                                     env vars or be replaced by uniquely identifiable placeholders.
0760       *                                     Set to "true" when you want to use the current ContainerBuilder
0761       *                                     directly, keep to "false" when the container is dumped instead.
0762       */
0763      public function compile(/*$resolveEnvPlaceholders = false*/)
0764      {
0765          if (1 <= \func_num_args()) {
0766              $resolveEnvPlaceholders = func_get_arg(0);
0767          } else {
0768              if (__CLASS__ !== static::class) {
0769                  $r = new \ReflectionMethod($this, __FUNCTION__);
0770                  if (__CLASS__ !== $r->getDeclaringClass()->getName() && (1 > $r->getNumberOfParameters() || 'resolveEnvPlaceholders' !== $r->getParameters()[0]->name)) {
0771                      @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);
0772                  }
0773              }
0774              $resolveEnvPlaceholders = false;
0775          }
0776          $compiler = $this->getCompiler();
0777   
0778          if ($this->trackResources) {
0779              foreach ($compiler->getPassConfig()->getPasses() as $pass) {
0780                  $this->addObjectResource($pass);
0781              }
0782          }
0783          $bag = $this->getParameterBag();
0784   
0785          if ($resolveEnvPlaceholders && $bag instanceof EnvPlaceholderParameterBag) {
0786              $compiler->addPass(new ResolveEnvPlaceholdersPass(), PassConfig::TYPE_AFTER_REMOVING, -1000);
0787          }
0788   
0789          $compiler->compile($this);
0790   
0791          foreach ($this->definitions as $id => $definition) {
0792              if ($this->trackResources && $definition->isLazy()) {
0793                  $this->getReflectionClass($definition->getClass());
0794              }
0795          }
0796   
0797          $this->extensionConfigs = [];
0798   
0799          if ($bag instanceof EnvPlaceholderParameterBag) {
0800              if ($resolveEnvPlaceholders) {
0801                  $this->parameterBag = new ParameterBag($this->resolveEnvPlaceholders($bag->all(), true));
0802              }
0803   
0804              $this->envPlaceholders = $bag->getEnvPlaceholders();
0805          }
0806   
0807          parent::compile();
0808   
0809          foreach ($this->definitions + $this->aliasDefinitions as $id => $definition) {
0810              if (!$definition->isPublic() || $definition->isPrivate()) {
0811                  $this->removedIds[$id] = true;
0812              }
0813          }
0814      }
0815   
0816      /**
0817       * {@inheritdoc}
0818       */
0819      public function getServiceIds()
0820      {
0821          return array_map('strval', array_unique(array_merge(array_keys($this->getDefinitions()), array_keys($this->aliasDefinitions), parent::getServiceIds())));
0822      }
0823   
0824      /**
0825       * Gets removed service or alias ids.
0826       *
0827       * @return array
0828       */
0829      public function getRemovedIds()
0830      {
0831          return $this->removedIds;
0832      }
0833   
0834      /**
0835       * Adds the service aliases.
0836       */
0837      public function addAliases(array $aliases)
0838      {
0839          foreach ($aliases as $alias => $id) {
0840              $this->setAlias($alias, $id);
0841          }
0842      }
0843   
0844      /**
0845       * Sets the service aliases.
0846       */
0847      public function setAliases(array $aliases)
0848      {
0849          $this->aliasDefinitions = [];
0850          $this->addAliases($aliases);
0851      }
0852   
0853      /**
0854       * Sets an alias for an existing service.
0855       *
0856       * @param string       $alias The alias to create
0857       * @param string|Alias $id    The service to alias
0858       *
0859       * @return Alias
0860       *
0861       * @throws InvalidArgumentException if the id is not a string or an Alias
0862       * @throws InvalidArgumentException if the alias is for itself
0863       */
0864      public function setAlias($alias, $id)
0865      {
0866          $alias = $this->normalizeId($alias);
0867   
0868          if ('' === $alias || '\\' === substr($alias, -1) || \strlen($alias) !== strcspn($alias, "\0\r\n'")) {
0869              throw new InvalidArgumentException(sprintf('Invalid alias id: "%s".', $alias));
0870          }
0871   
0872          if (\is_string($id)) {
0873              $id = new Alias($this->normalizeId($id));
0874          } elseif (!$id instanceof Alias) {
0875              throw new InvalidArgumentException('$id must be a string, or an Alias object.');
0876          }
0877   
0878          if ($alias === (string) $id) {
0879              throw new InvalidArgumentException(sprintf('An alias can not reference itself, got a circular reference on "%s".', $alias));
0880          }
0881   
0882          unset($this->definitions[$alias], $this->removedIds[$alias]);
0883   
0884          return $this->aliasDefinitions[$alias] = $id;
0885      }
0886   
0887      /**
0888       * Removes an alias.
0889       *
0890       * @param string $alias The alias to remove
0891       */
0892      public function removeAlias($alias)
0893      {
0894          if (isset($this->aliasDefinitions[$alias = $this->normalizeId($alias)])) {
0895              unset($this->aliasDefinitions[$alias]);
0896              $this->removedIds[$alias] = true;
0897          }
0898      }
0899   
0900      /**
0901       * Returns true if an alias exists under the given identifier.
0902       *
0903       * @param string $id The service identifier
0904       *
0905       * @return bool true if the alias exists, false otherwise
0906       */
0907      public function hasAlias($id)
0908      {
0909          return isset($this->aliasDefinitions[$this->normalizeId($id)]);
0910      }
0911   
0912      /**
0913       * Gets all defined aliases.
0914       *
0915       * @return Alias[] An array of aliases
0916       */
0917      public function getAliases()
0918      {
0919          return $this->aliasDefinitions;
0920      }
0921   
0922      /**
0923       * Gets an alias.
0924       *
0925       * @param string $id The service identifier
0926       *
0927       * @return Alias An Alias instance
0928       *
0929       * @throws InvalidArgumentException if the alias does not exist
0930       */
0931      public function getAlias($id)
0932      {
0933          $id = $this->normalizeId($id);
0934   
0935          if (!isset($this->aliasDefinitions[$id])) {
0936              throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id));
0937          }
0938   
0939          return $this->aliasDefinitions[$id];
0940      }
0941   
0942      /**
0943       * Registers a service definition.
0944       *
0945       * This methods allows for simple registration of service definition
0946       * with a fluid interface.
0947       *
0948       * @param string      $id    The service identifier
0949       * @param string|null $class The service class
0950       *
0951       * @return Definition A Definition instance
0952       */
0953      public function register($id, $class = null)
0954      {
0955          return $this->setDefinition($id, new Definition($class));
0956      }
0957   
0958      /**
0959       * Registers an autowired service definition.
0960       *
0961       * This method implements a shortcut for using setDefinition() with
0962       * an autowired definition.
0963       *
0964       * @param string      $id    The service identifier
0965       * @param string|null $class The service class
0966       *
0967       * @return Definition The created definition
0968       */
0969      public function autowire($id, $class = null)
0970      {
0971          return $this->setDefinition($id, (new Definition($class))->setAutowired(true));
0972      }
0973   
0974      /**
0975       * Adds the service definitions.
0976       *
0977       * @param Definition[] $definitions An array of service definitions
0978       */
0979      public function addDefinitions(array $definitions)
0980      {
0981          foreach ($definitions as $id => $definition) {
0982              $this->setDefinition($id, $definition);
0983          }
0984      }
0985   
0986      /**
0987       * Sets the service definitions.
0988       *
0989       * @param Definition[] $definitions An array of service definitions
0990       */
0991      public function setDefinitions(array $definitions)
0992      {
0993          $this->definitions = [];
0994          $this->addDefinitions($definitions);
0995      }
0996   
0997      /**
0998       * Gets all service definitions.
0999       *
1000       * @return Definition[] An array of Definition instances
1001       */
1002      public function getDefinitions()
1003      {
1004          return $this->definitions;
1005      }
1006   
1007      /**
1008       * Sets a service definition.
1009       *
1010       * @param string     $id         The service identifier
1011       * @param Definition $definition A Definition instance
1012       *
1013       * @return Definition the service definition
1014       *
1015       * @throws BadMethodCallException When this ContainerBuilder is compiled
1016       */
1017      public function setDefinition($id, Definition $definition)
1018      {
1019          if ($this->isCompiled()) {
1020              throw new BadMethodCallException('Adding definition to a compiled container is not allowed.');
1021          }
1022   
1023          $id = $this->normalizeId($id);
1024   
1025          if ('' === $id || '\\' === substr($id, -1) || \strlen($id) !== strcspn($id, "\0\r\n'")) {
1026              throw new InvalidArgumentException(sprintf('Invalid service id: "%s".', $id));
1027          }
1028   
1029          unset($this->aliasDefinitions[$id], $this->removedIds[$id]);
1030   
1031          return $this->definitions[$id] = $definition;
1032      }
1033   
1034      /**
1035       * Returns true if a service definition exists under the given identifier.
1036       *
1037       * @param string $id The service identifier
1038       *
1039       * @return bool true if the service definition exists, false otherwise
1040       */
1041      public function hasDefinition($id)
1042      {
1043          return isset($this->definitions[$this->normalizeId($id)]);
1044      }
1045   
1046      /**
1047       * Gets a service definition.
1048       *
1049       * @param string $id The service identifier
1050       *
1051       * @return Definition A Definition instance
1052       *
1053       * @throws ServiceNotFoundException if the service definition does not exist
1054       */
1055      public function getDefinition($id)
1056      {
1057          $id = $this->normalizeId($id);
1058   
1059          if (!isset($this->definitions[$id])) {
1060              throw new ServiceNotFoundException($id);
1061          }
1062   
1063          return $this->definitions[$id];
1064      }
1065   
1066      /**
1067       * Gets a service definition by id or alias.
1068       *
1069       * The method "unaliases" recursively to return a Definition instance.
1070       *
1071       * @param string $id The service identifier or alias
1072       *
1073       * @return Definition A Definition instance
1074       *
1075       * @throws ServiceNotFoundException if the service definition does not exist
1076       */
1077      public function findDefinition($id)
1078      {
1079          $id = $this->normalizeId($id);
1080   
1081          $seen = [];
1082          while (isset($this->aliasDefinitions[$id])) {
1083              $id = (string) $this->aliasDefinitions[$id];
1084   
1085              if (isset($seen[$id])) {
1086                  $seen = array_values($seen);
1087                  $seen = \array_slice($seen, array_search($id, $seen));
1088                  $seen[] = $id;
1089   
1090                  throw new ServiceCircularReferenceException($id, $seen);
1091              }
1092   
1093              $seen[$id] = $id;
1094          }
1095   
1096          return $this->getDefinition($id);
1097      }
1098   
1099      /**
1100       * Creates a service for a service definition.
1101       *
1102       * @param Definition $definition A service definition instance
1103       * @param string     $id         The service identifier
1104       * @param bool       $tryProxy   Whether to try proxying the service with a lazy proxy
1105       *
1106       * @return mixed The service described by the service definition
1107       *
1108       * @throws RuntimeException         When the factory definition is incomplete
1109       * @throws RuntimeException         When the service is a synthetic service
1110       * @throws InvalidArgumentException When configure callable is not callable
1111       */
1112      private function createService(Definition $definition, array &$inlineServices, $isConstructorArgument = false, $id = null, $tryProxy = true)
1113      {
1114          if (null === $id && isset($inlineServices[$h = spl_object_hash($definition)])) {
1115              return $inlineServices[$h];
1116          }
1117   
1118          if ($definition instanceof ChildDefinition) {
1119              throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
1120          }
1121   
1122          if ($definition->isSynthetic()) {
1123              throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
1124          }
1125   
1126          if ($definition->isDeprecated()) {
1127              @trigger_error($definition->getDeprecationMessage($id), \E_USER_DEPRECATED);
1128          }
1129   
1130          if ($tryProxy && $definition->isLazy() && !$tryProxy = !($proxy = $this->proxyInstantiator) || $proxy instanceof RealServiceInstantiator) {
1131              $proxy = $proxy->instantiateProxy(
1132                  $this,
1133                  $definition,
1134                  $id, function () use ($definition, &$inlineServices, $id) {
1135                      return $this->createService($definition, $inlineServices, true, $id, false);
1136                  }
1137              );
1138              $this->shareService($definition, $proxy, $id, $inlineServices);
1139   
1140              return $proxy;
1141          }
1142   
1143          $parameterBag = $this->getParameterBag();
1144   
1145          if (null !== $definition->getFile()) {
1146              require_once $parameterBag->resolveValue($definition->getFile());
1147          }
1148   
1149          $arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlineServices, $isConstructorArgument);
1150   
1151          if (null !== $factory = $definition->getFactory()) {
1152              if (\is_array($factory)) {
1153                  $factory = [$this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlineServices, $isConstructorArgument), $factory[1]];
1154              } elseif (!\is_string($factory)) {
1155                  throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory.', $id));
1156              }
1157          }
1158   
1159          if (null !== $id && $definition->isShared() && isset($this->services[$id]) && ($tryProxy || !$definition->isLazy())) {
1160              return $this->services[$id];
1161          }
1162   
1163          if (null !== $factory) {
1164              $service = \call_user_func_array($factory, $arguments);
1165   
1166              if (!$definition->isDeprecated() && \is_array($factory) && \is_string($factory[0])) {
1167                  $r = new \ReflectionClass($factory[0]);
1168   
1169                  if (0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
1170                      @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);
1171                  }
1172              }
1173          } else {
1174              $r = new \ReflectionClass($class = $parameterBag->resolveValue($definition->getClass()));
1175   
1176              $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs(array_values($arguments));
1177              // don't trigger deprecations for internal uses
1178              // @deprecated since version 3.3, to be removed in 4.0 along with the deprecated class
1179              $deprecationAllowlist = ['event_dispatcher' => ContainerAwareEventDispatcher::class];
1180   
1181              if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ") && (!isset($deprecationAllowlist[$id]) || $deprecationAllowlist[$id] !== $class)) {
1182                  @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);
1183              }
1184          }
1185   
1186          if ($tryProxy || !$definition->isLazy()) {
1187              // share only if proxying failed, or if not a proxy
1188              $this->shareService($definition, $service, $id, $inlineServices);
1189          }
1190   
1191          $properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlineServices);
1192          foreach ($properties as $name => $value) {
1193              $service->$name = $value;
1194          }
1195   
1196          foreach ($definition->getMethodCalls() as $call) {
1197              $this->callMethod($service, $call, $inlineServices);
1198          }
1199   
1200          if ($callable = $definition->getConfigurator()) {
1201              if (\is_array($callable)) {
1202                  $callable[0] = $parameterBag->resolveValue($callable[0]);
1203   
1204                  if ($callable[0] instanceof Reference) {
1205                      $callable[0] = $this->doGet((string) $callable[0], $callable[0]->getInvalidBehavior(), $inlineServices);
1206                  } elseif ($callable[0] instanceof Definition) {
1207                      $callable[0] = $this->createService($callable[0], $inlineServices);
1208                  }
1209              }
1210   
1211              if (!\is_callable($callable)) {
1212                  throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', \get_class($service)));
1213              }
1214   
1215              \call_user_func($callable, $service);
1216          }
1217   
1218          return $service;
1219      }
1220   
1221      /**
1222       * Replaces service references by the real service instance and evaluates expressions.
1223       *
1224       * @param mixed $value A value
1225       *
1226       * @return mixed The same value with all service references replaced by
1227       *               the real service instances and all expressions evaluated
1228       */
1229      public function resolveServices($value)
1230      {
1231          return $this->doResolveServices($value);
1232      }
1233   
1234      private function doResolveServices($value, array &$inlineServices = [], $isConstructorArgument = false)
1235      {
1236          if (\is_array($value)) {
1237              foreach ($value as $k => $v) {
1238                  $value[$k] = $this->doResolveServices($v, $inlineServices, $isConstructorArgument);
1239              }
1240          } elseif ($value instanceof ServiceClosureArgument) {
1241              $reference = $value->getValues()[0];
1242              $value = function () use ($reference) {
1243                  return $this->resolveServices($reference);
1244              };
1245          } elseif ($value instanceof IteratorArgument) {
1246              $value = new RewindableGenerator(function () use ($value) {
1247                  foreach ($value->getValues() as $k => $v) {
1248                      foreach (self::getServiceConditionals($v) as $s) {
1249                          if (!$this->has($s)) {
1250                              continue 2;
1251                          }
1252                      }
1253                      foreach (self::getInitializedConditionals($v) as $s) {
1254                          if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
1255                              continue 2;
1256                          }
1257                      }
1258   
1259                      yield $k => $this->resolveServices($v);
1260                  }
1261              }, function () use ($value) {
1262                  $count = 0;
1263                  foreach ($value->getValues() as $v) {
1264                      foreach (self::getServiceConditionals($v) as $s) {
1265                          if (!$this->has($s)) {
1266                              continue 2;
1267                          }
1268                      }
1269                      foreach (self::getInitializedConditionals($v) as $s) {
1270                          if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
1271                              continue 2;
1272                          }
1273                      }
1274   
1275                      ++$count;
1276                  }
1277   
1278                  return $count;
1279              });
1280          } elseif ($value instanceof Reference) {
1281              $value = $this->doGet((string) $value, $value->getInvalidBehavior(), $inlineServices, $isConstructorArgument);
1282          } elseif ($value instanceof Definition) {
1283              $value = $this->createService($value, $inlineServices, $isConstructorArgument);
1284          } elseif ($value instanceof Parameter) {
1285              $value = $this->getParameter((string) $value);
1286          } elseif ($value instanceof Expression) {
1287              $value = $this->getExpressionLanguage()->evaluate($value, ['container' => $this]);
1288          }
1289   
1290          return $value;
1291      }
1292   
1293      /**
1294       * Returns service ids for a given tag.
1295       *
1296       * Example:
1297       *
1298       *     $container->register('foo')->addTag('my.tag', ['hello' => 'world']);
1299       *
1300       *     $serviceIds = $container->findTaggedServiceIds('my.tag');
1301       *     foreach ($serviceIds as $serviceId => $tags) {
1302       *         foreach ($tags as $tag) {
1303       *             echo $tag['hello'];
1304       *         }
1305       *     }
1306       *
1307       * @param string $name
1308       * @param bool   $throwOnAbstract
1309       *
1310       * @return array An array of tags with the tagged service as key, holding a list of attribute arrays
1311       */
1312      public function findTaggedServiceIds($name, $throwOnAbstract = false)
1313      {
1314          $this->usedTags[] = $name;
1315          $tags = [];
1316          foreach ($this->getDefinitions() as $id => $definition) {
1317              if ($definition->hasTag($name)) {
1318                  if ($throwOnAbstract && $definition->isAbstract()) {
1319                      throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must not be abstract.', $id, $name));
1320                  }
1321                  $tags[$id] = $definition->getTag($name);
1322              }
1323          }
1324   
1325          return $tags;
1326      }
1327   
1328      /**
1329       * Returns all tags the defined services use.
1330       *
1331       * @return array An array of tags
1332       */
1333      public function findTags()
1334      {
1335          $tags = [];
1336          foreach ($this->getDefinitions() as $id => $definition) {
1337              $tags = array_merge(array_keys($definition->getTags()), $tags);
1338          }
1339   
1340          return array_unique($tags);
1341      }
1342   
1343      /**
1344       * Returns all tags not queried by findTaggedServiceIds.
1345       *
1346       * @return string[] An array of tags
1347       */
1348      public function findUnusedTags()
1349      {
1350          return array_values(array_diff($this->findTags(), $this->usedTags));
1351      }
1352   
1353      public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
1354      {
1355          $this->expressionLanguageProviders[] = $provider;
1356      }
1357   
1358      /**
1359       * @return ExpressionFunctionProviderInterface[]
1360       */
1361      public function getExpressionLanguageProviders()
1362      {
1363          return $this->expressionLanguageProviders;
1364      }
1365   
1366      /**
1367       * Returns a ChildDefinition that will be used for autoconfiguring the interface/class.
1368       *
1369       * @param string $interface The class or interface to match
1370       *
1371       * @return ChildDefinition
1372       */
1373      public function registerForAutoconfiguration($interface)
1374      {
1375          if (!isset($this->autoconfiguredInstanceof[$interface])) {
1376              $this->autoconfiguredInstanceof[$interface] = new ChildDefinition('');
1377          }
1378   
1379          return $this->autoconfiguredInstanceof[$interface];
1380      }
1381   
1382      /**
1383       * Returns an array of ChildDefinition[] keyed by interface.
1384       *
1385       * @return ChildDefinition[]
1386       */
1387      public function getAutoconfiguredInstanceof()
1388      {
1389          return $this->autoconfiguredInstanceof;
1390      }
1391   
1392      /**
1393       * Resolves env parameter placeholders in a string or an array.
1394       *
1395       * @param mixed            $value     The value to resolve
1396       * @param string|true|null $format    A sprintf() format returning the replacement for each env var name or
1397       *                                    null to resolve back to the original "%env(VAR)%" format or
1398       *                                    true to resolve to the actual values of the referenced env vars
1399       * @param array            &$usedEnvs Env vars found while resolving are added to this array
1400       *
1401       * @return mixed The value with env parameters resolved if a string or an array is passed
1402       */
1403      public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs = null)
1404      {
1405          if (null === $format) {
1406              $format = '%%env(%s)%%';
1407          }
1408   
1409          $bag = $this->getParameterBag();
1410          if (true === $format) {
1411              $value = $bag->resolveValue($value);
1412          }
1413   
1414          if (\is_array($value)) {
1415              $result = [];
1416              foreach ($value as $k => $v) {
1417                  $result[\is_string($k) ? $this->resolveEnvPlaceholders($k, $format, $usedEnvs) : $k] = $this->resolveEnvPlaceholders($v, $format, $usedEnvs);
1418              }
1419   
1420              return $result;
1421          }
1422   
1423          if (!\is_string($value) || 38 > \strlen($value)) {
1424              return $value;
1425          }
1426          $envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : $this->envPlaceholders;
1427   
1428          $completed = false;
1429          foreach ($envPlaceholders as $env => $placeholders) {
1430              foreach ($placeholders as $placeholder) {
1431                  if (false !== stripos($value, $placeholder)) {
1432                      if (true === $format) {
1433                          $resolved = $bag->escapeValue($this->getEnv($env));
1434                      } else {
1435                          $resolved = sprintf($format, $env);
1436                      }
1437                      if ($placeholder === $value) {
1438                          $value = $resolved;
1439                          $completed = true;
1440                      } else {
1441                          if (!\is_string($resolved) && !is_numeric($resolved)) {
1442                              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)));
1443                          }
1444                          $value = str_ireplace($placeholder, $resolved, $value);
1445                      }
1446                      $usedEnvs[$env] = $env;
1447                      $this->envCounters[$env] = isset($this->envCounters[$env]) ? 1 + $this->envCounters[$env] : 1;
1448   
1449                      if ($completed) {
1450                          break 2;
1451                      }
1452                  }
1453              }
1454          }
1455   
1456          return $value;
1457      }
1458   
1459      /**
1460       * Get statistics about env usage.
1461       *
1462       * @return int[] The number of time each env vars has been resolved
1463       */
1464      public function getEnvCounters()
1465      {
1466          $bag = $this->getParameterBag();
1467          $envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : $this->envPlaceholders;
1468   
1469          foreach ($envPlaceholders as $env => $placeholders) {
1470              if (!isset($this->envCounters[$env])) {
1471                  $this->envCounters[$env] = 0;
1472              }
1473          }
1474   
1475          return $this->envCounters;
1476      }
1477   
1478      /**
1479       * @internal
1480       */
1481      public function getNormalizedIds()
1482      {
1483          $normalizedIds = [];
1484   
1485          foreach ($this->normalizedIds as $k => $v) {
1486              if ($v !== (string) $k) {
1487                  $normalizedIds[$k] = $v;
1488              }
1489          }
1490   
1491          return $normalizedIds;
1492      }
1493   
1494      /**
1495       * @final
1496       */
1497      public function log(CompilerPassInterface $pass, $message)
1498      {
1499          $this->getCompiler()->log($pass, $this->resolveEnvPlaceholders($message));
1500      }
1501   
1502      /**
1503       * {@inheritdoc}
1504       */
1505      public function normalizeId($id)
1506      {
1507          if (!\is_string($id)) {
1508              $id = (string) $id;
1509          }
1510   
1511          return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || isset($this->removedIds[$id]) ? $id : parent::normalizeId($id);
1512      }
1513   
1514      /**
1515       * Gets removed binding ids.
1516       *
1517       * @return array
1518       *
1519       * @internal
1520       */
1521      public function getRemovedBindingIds()
1522      {
1523          return $this->removedBindingIds;
1524      }
1525   
1526      /**
1527       * Removes bindings for a service.
1528       *
1529       * @param string $id The service identifier
1530       *
1531       * @internal
1532       */
1533      public function removeBindings($id)
1534      {
1535          if ($this->hasDefinition($id)) {
1536              foreach ($this->getDefinition($id)->getBindings() as $key => $binding) {
1537                  list(, $bindingId) = $binding->getValues();
1538                  $this->removedBindingIds[(int) $bindingId] = true;
1539              }
1540          }
1541      }
1542   
1543      /**
1544       * Returns the Service Conditionals.
1545       *
1546       * @param mixed $value An array of conditionals to return
1547       *
1548       * @return array An array of Service conditionals
1549       *
1550       * @internal since version 3.4
1551       */
1552      public static function getServiceConditionals($value)
1553      {
1554          $services = [];
1555   
1556          if (\is_array($value)) {
1557              foreach ($value as $v) {
1558                  $services = array_unique(array_merge($services, self::getServiceConditionals($v)));
1559              }
1560          } elseif ($value instanceof Reference && ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) {
1561              $services[] = (string) $value;
1562          }
1563   
1564          return $services;
1565      }
1566   
1567      /**
1568       * Returns the initialized conditionals.
1569       *
1570       * @param mixed $value An array of conditionals to return
1571       *
1572       * @return array An array of uninitialized conditionals
1573       *
1574       * @internal
1575       */
1576      public static function getInitializedConditionals($value)
1577      {
1578          $services = [];
1579   
1580          if (\is_array($value)) {
1581              foreach ($value as $v) {
1582                  $services = array_unique(array_merge($services, self::getInitializedConditionals($v)));
1583              }
1584          } elseif ($value instanceof Reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()) {
1585              $services[] = (string) $value;
1586          }
1587   
1588          return $services;
1589      }
1590   
1591      /**
1592       * Computes a reasonably unique hash of a value.
1593       *
1594       * @param mixed $value A serializable value
1595       *
1596       * @return string
1597       */
1598      public static function hash($value)
1599      {
1600          $hash = substr(base64_encode(hash('sha256', serialize($value), true)), 0, 7);
1601   
1602          return str_replace(['/', '+'], ['.', '_'], strtolower($hash));
1603      }
1604   
1605      /**
1606       * {@inheritdoc}
1607       */
1608      protected function getEnv($name)
1609      {
1610          $value = parent::getEnv($name);
1611          $bag = $this->getParameterBag();
1612   
1613          if (!\is_string($value) || !$bag instanceof EnvPlaceholderParameterBag) {
1614              return $value;
1615          }
1616   
1617          foreach ($bag->getEnvPlaceholders() as $env => $placeholders) {
1618              if (isset($placeholders[$value])) {
1619                  $bag = new ParameterBag($bag->all());
1620   
1621                  return $bag->unescapeValue($bag->get("env($name)"));
1622              }
1623          }
1624   
1625          $this->resolving["env($name)"] = true;
1626          try {
1627              return $bag->unescapeValue($this->resolveEnvPlaceholders($bag->escapeValue($value), true));
1628          } finally {
1629              unset($this->resolving["env($name)"]);
1630          }
1631      }
1632   
1633      private function callMethod($service, $call, array &$inlineServices)
1634      {
1635          foreach (self::getServiceConditionals($call[1]) as $s) {
1636              if (!$this->has($s)) {
1637                  return;
1638              }
1639          }
1640          foreach (self::getInitializedConditionals($call[1]) as $s) {
1641              if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE, $inlineServices)) {
1642                  return;
1643              }
1644          }
1645   
1646          \call_user_func_array([$service, $call[0]], $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlineServices));
1647      }
1648   
1649      /**
1650       * Shares a given service in the container.
1651       *
1652       * @param mixed       $service
1653       * @param string|null $id
1654       */
1655      private function shareService(Definition $definition, $service, $id, array &$inlineServices)
1656      {
1657          $inlineServices[null !== $id ? $id : spl_object_hash($definition)] = $service;
1658   
1659          if (null !== $id && $definition->isShared()) {
1660              $this->services[$id] = $service;
1661              unset($this->loading[$id]);
1662          }
1663      }
1664   
1665      private function getExpressionLanguage()
1666      {
1667          if (null === $this->expressionLanguage) {
1668              if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
1669                  throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
1670              }
1671              $this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders);
1672          }
1673   
1674          return $this->expressionLanguage;
1675      }
1676   
1677      private function inVendors($path)
1678      {
1679          if (null === $this->vendors) {
1680              $resource = new ComposerResource();
1681              $this->vendors = $resource->getVendors();
1682              $this->addResource($resource);
1683          }
1684          $path = realpath($path) ?: $path;
1685   
1686          foreach ($this->vendors as $vendor) {
1687              if (0 === strpos($path, $vendor) && false !== strpbrk(substr($path, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
1688                  return true;
1689              }
1690          }
1691   
1692          return false;
1693      }
1694  }
1695