Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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: 09.10.2024, 12:54 - Dateigröße: 35.42 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 Symfony\Component\DependencyInjection\Compiler\Compiler;
0015  use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
0016  use Symfony\Component\DependencyInjection\Compiler\PassConfig;
0017  use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
0018  use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
0019  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
0020  use Symfony\Component\DependencyInjection\Exception\LogicException;
0021  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
0022  use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
0023  use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
0024  use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
0025  use Symfony\Component\Config\Resource\FileResource;
0026  use Symfony\Component\Config\Resource\ResourceInterface;
0027  use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
0028  use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
0029  use Symfony\Component\ExpressionLanguage\Expression;
0030  use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
0031   
0032  /**
0033   * ContainerBuilder is a DI container that provides an API to easily describe services.
0034   *
0035   * @author Fabien Potencier <fabien@symfony.com>
0036   */
0037  class ContainerBuilder extends Container implements TaggedContainerInterface
0038  {
0039      /**
0040       * @var ExtensionInterface[]
0041       */
0042      private $extensions = array();
0043   
0044      /**
0045       * @var ExtensionInterface[]
0046       */
0047      private $extensionsByNs = array();
0048   
0049      /**
0050       * @var Definition[]
0051       */
0052      private $definitions = array();
0053   
0054      /**
0055       * @var Definition[]
0056       */
0057      private $obsoleteDefinitions = array();
0058   
0059      /**
0060       * @var Alias[]
0061       */
0062      private $aliasDefinitions = array();
0063   
0064      /**
0065       * @var ResourceInterface[]
0066       */
0067      private $resources = array();
0068   
0069      private $extensionConfigs = array();
0070   
0071      /**
0072       * @var Compiler
0073       */
0074      private $compiler;
0075   
0076      private $trackResources = true;
0077   
0078      /**
0079       * @var InstantiatorInterface|null
0080       */
0081      private $proxyInstantiator;
0082   
0083      /**
0084       * @var ExpressionLanguage|null
0085       */
0086      private $expressionLanguage;
0087   
0088      /**
0089       * @var ExpressionFunctionProviderInterface[]
0090       */
0091      private $expressionLanguageProviders = array();
0092   
0093      /**
0094       * @var string[] with tag names used by findTaggedServiceIds
0095       */
0096      private $usedTags = array();
0097   
0098      /**
0099       * Sets the track resources flag.
0100       *
0101       * If you are not using the loaders and therefore don't want
0102       * to depend on the Config component, set this flag to false.
0103       *
0104       * @param bool $track true if you want to track resources, false otherwise
0105       */
0106      public function setResourceTracking($track)
0107      {
0108          $this->trackResources = (bool) $track;
0109      }
0110   
0111      /**
0112       * Checks if resources are tracked.
0113       *
0114       * @return bool true if resources are tracked, false otherwise
0115       */
0116      public function isTrackingResources()
0117      {
0118          return $this->trackResources;
0119      }
0120   
0121      /**
0122       * Sets the instantiator to be used when fetching proxies.
0123       *
0124       * @param InstantiatorInterface $proxyInstantiator
0125       */
0126      public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator)
0127      {
0128          $this->proxyInstantiator = $proxyInstantiator;
0129      }
0130   
0131      /**
0132       * Registers an extension.
0133       *
0134       * @param ExtensionInterface $extension An extension instance
0135       */
0136      public function registerExtension(ExtensionInterface $extension)
0137      {
0138          $this->extensions[$extension->getAlias()] = $extension;
0139   
0140          if (false !== $extension->getNamespace()) {
0141              $this->extensionsByNs[$extension->getNamespace()] = $extension;
0142          }
0143      }
0144   
0145      /**
0146       * Returns an extension by alias or namespace.
0147       *
0148       * @param string $name An alias or a namespace
0149       *
0150       * @return ExtensionInterface An extension instance
0151       *
0152       * @throws LogicException if the extension is not registered
0153       */
0154      public function getExtension($name)
0155      {
0156          if (isset($this->extensions[$name])) {
0157              return $this->extensions[$name];
0158          }
0159   
0160          if (isset($this->extensionsByNs[$name])) {
0161              return $this->extensionsByNs[$name];
0162          }
0163   
0164          throw new LogicException(sprintf('Container extension "%s" is not registered', $name));
0165      }
0166   
0167      /**
0168       * Returns all registered extensions.
0169       *
0170       * @return ExtensionInterface[] An array of ExtensionInterface
0171       */
0172      public function getExtensions()
0173      {
0174          return $this->extensions;
0175      }
0176   
0177      /**
0178       * Checks if we have an extension.
0179       *
0180       * @param string $name The name of the extension
0181       *
0182       * @return bool If the extension exists
0183       */
0184      public function hasExtension($name)
0185      {
0186          return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]);
0187      }
0188   
0189      /**
0190       * Returns an array of resources loaded to build this configuration.
0191       *
0192       * @return ResourceInterface[] An array of resources
0193       */
0194      public function getResources()
0195      {
0196          return array_unique($this->resources);
0197      }
0198   
0199      /**
0200       * Adds a resource for this configuration.
0201       *
0202       * @param ResourceInterface $resource A resource instance
0203       *
0204       * @return ContainerBuilder The current instance
0205       */
0206      public function addResource(ResourceInterface $resource)
0207      {
0208          if (!$this->trackResources) {
0209              return $this;
0210          }
0211   
0212          $this->resources[] = $resource;
0213   
0214          return $this;
0215      }
0216   
0217      /**
0218       * Sets the resources for this configuration.
0219       *
0220       * @param ResourceInterface[] $resources An array of resources
0221       *
0222       * @return ContainerBuilder The current instance
0223       */
0224      public function setResources(array $resources)
0225      {
0226          if (!$this->trackResources) {
0227              return $this;
0228          }
0229   
0230          $this->resources = $resources;
0231   
0232          return $this;
0233      }
0234   
0235      /**
0236       * Adds the object class hierarchy as resources.
0237       *
0238       * @param object $object An object instance
0239       *
0240       * @return ContainerBuilder The current instance
0241       */
0242      public function addObjectResource($object)
0243      {
0244          if ($this->trackResources) {
0245              $this->addClassResource(new \ReflectionClass($object));
0246          }
0247   
0248          return $this;
0249      }
0250   
0251      /**
0252       * Adds the given class hierarchy as resources.
0253       *
0254       * @param \ReflectionClass $class
0255       *
0256       * @return ContainerBuilder The current instance
0257       */
0258      public function addClassResource(\ReflectionClass $class)
0259      {
0260          if (!$this->trackResources) {
0261              return $this;
0262          }
0263   
0264          do {
0265              if (is_file($class->getFileName())) {
0266                  $this->addResource(new FileResource($class->getFileName()));
0267              }
0268          } while ($class = $class->getParentClass());
0269   
0270          return $this;
0271      }
0272   
0273      /**
0274       * Loads the configuration for an extension.
0275       *
0276       * @param string $extension The extension alias or namespace
0277       * @param array  $values    An array of values that customizes the extension
0278       *
0279       * @return ContainerBuilder The current instance
0280       *
0281       * @throws BadMethodCallException When this ContainerBuilder is frozen
0282       * @throws \LogicException        if the container is frozen
0283       */
0284      public function loadFromExtension($extension, array $values = array())
0285      {
0286          if ($this->isFrozen()) {
0287              throw new BadMethodCallException('Cannot load from an extension on a frozen container.');
0288          }
0289   
0290          $namespace = $this->getExtension($extension)->getAlias();
0291   
0292          $this->extensionConfigs[$namespace][] = $values;
0293   
0294          return $this;
0295      }
0296   
0297      /**
0298       * Adds a compiler pass.
0299       *
0300       * @param CompilerPassInterface $pass A compiler pass
0301       * @param string                $type The type of compiler pass
0302       *
0303       * @return ContainerBuilder The current instance
0304       */
0305      public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
0306      {
0307          $this->getCompiler()->addPass($pass, $type);
0308   
0309          $this->addObjectResource($pass);
0310   
0311          return $this;
0312      }
0313   
0314      /**
0315       * Returns the compiler pass config which can then be modified.
0316       *
0317       * @return PassConfig The compiler pass config
0318       */
0319      public function getCompilerPassConfig()
0320      {
0321          return $this->getCompiler()->getPassConfig();
0322      }
0323   
0324      /**
0325       * Returns the compiler.
0326       *
0327       * @return Compiler The compiler
0328       */
0329      public function getCompiler()
0330      {
0331          if (null === $this->compiler) {
0332              $this->compiler = new Compiler();
0333          }
0334   
0335          return $this->compiler;
0336      }
0337   
0338      /**
0339       * Returns all Scopes.
0340       *
0341       * @return array An array of scopes
0342       *
0343       * @deprecated since version 2.8, to be removed in 3.0.
0344       */
0345      public function getScopes($triggerDeprecationError = true)
0346      {
0347          if ($triggerDeprecationError) {
0348              @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
0349          }
0350   
0351          return $this->scopes;
0352      }
0353   
0354      /**
0355       * Returns all Scope children.
0356       *
0357       * @return array An array of scope children
0358       *
0359       * @deprecated since version 2.8, to be removed in 3.0.
0360       */
0361      public function getScopeChildren($triggerDeprecationError = true)
0362      {
0363          if ($triggerDeprecationError) {
0364              @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
0365          }
0366   
0367          return $this->scopeChildren;
0368      }
0369   
0370      /**
0371       * Sets a service.
0372       *
0373       * Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
0374       *
0375       * @param string $id      The service identifier
0376       * @param object $service The service instance
0377       * @param string $scope   The scope
0378       *
0379       * @throws BadMethodCallException When this ContainerBuilder is frozen
0380       */
0381      public function set($id, $service, $scope = self::SCOPE_CONTAINER)
0382      {
0383          $id = strtolower($id);
0384          $set = isset($this->definitions[$id]);
0385   
0386          if ($this->isFrozen() && ($set || isset($this->obsoleteDefinitions[$id])) && !$this->{$set ? 'definitions' : 'obsoleteDefinitions'}[$id]->isSynthetic()) {
0387              // setting a synthetic service on a frozen container is alright
0388              throw new BadMethodCallException(sprintf('Setting service "%s" on a frozen container is not allowed.', $id));
0389          }
0390   
0391          if ($set) {
0392              $this->obsoleteDefinitions[$id] = $this->definitions[$id];
0393          }
0394   
0395          unset($this->definitions[$id], $this->aliasDefinitions[$id]);
0396   
0397          parent::set($id, $service, $scope);
0398   
0399          if (isset($this->obsoleteDefinitions[$id]) && $this->obsoleteDefinitions[$id]->isSynchronized(false)) {
0400              $this->synchronize($id);
0401          }
0402      }
0403   
0404      /**
0405       * Removes a service definition.
0406       *
0407       * @param string $id The service identifier
0408       */
0409      public function removeDefinition($id)
0410      {
0411          unset($this->definitions[strtolower($id)]);
0412      }
0413   
0414      /**
0415       * Returns true if the given service is defined.
0416       *
0417       * @param string $id The service identifier
0418       *
0419       * @return bool true if the service is defined, false otherwise
0420       */
0421      public function has($id)
0422      {
0423          $id = strtolower($id);
0424   
0425          return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || parent::has($id);
0426      }
0427   
0428      /**
0429       * Gets a service.
0430       *
0431       * @param string $id              The service identifier
0432       * @param int    $invalidBehavior The behavior when the service does not exist
0433       *
0434       * @return object The associated service
0435       *
0436       * @throws InvalidArgumentException          when no definitions are available
0437       * @throws ServiceCircularReferenceException When a circular reference is detected
0438       * @throws ServiceNotFoundException          When the service is not defined
0439       * @throws \Exception
0440       *
0441       * @see Reference
0442       */
0443      public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
0444      {
0445          $id = strtolower($id);
0446   
0447          if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
0448              return $service;
0449          }
0450   
0451          if (!array_key_exists($id, $this->definitions) && isset($this->aliasDefinitions[$id])) {
0452              return $this->get($this->aliasDefinitions[$id]);
0453          }
0454   
0455          try {
0456              $definition = $this->getDefinition($id);
0457          } catch (ServiceNotFoundException $e) {
0458              if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
0459                  return;
0460              }
0461   
0462              throw $e;
0463          }
0464   
0465          $this->loading[$id] = true;
0466   
0467          try {
0468              $service = $this->createService($definition, $id);
0469          } catch (\Exception $e) {
0470              unset($this->loading[$id]);
0471   
0472              if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
0473                  return;
0474              }
0475   
0476              throw $e;
0477          } catch (\Throwable $e) {
0478              unset($this->loading[$id]);
0479   
0480              throw $e;
0481          }
0482   
0483          unset($this->loading[$id]);
0484   
0485          return $service;
0486      }
0487   
0488      /**
0489       * Merges a ContainerBuilder with the current ContainerBuilder configuration.
0490       *
0491       * Service definitions overrides the current defined ones.
0492       *
0493       * But for parameters, they are overridden by the current ones. It allows
0494       * the parameters passed to the container constructor to have precedence
0495       * over the loaded ones.
0496       *
0497       * $container = new ContainerBuilder(array('foo' => 'bar'));
0498       * $loader = new LoaderXXX($container);
0499       * $loader->load('resource_name');
0500       * $container->register('foo', new stdClass());
0501       *
0502       * In the above example, even if the loaded resource defines a foo
0503       * parameter, the value will still be 'bar' as defined in the ContainerBuilder
0504       * constructor.
0505       *
0506       * @param ContainerBuilder $container The ContainerBuilder instance to merge
0507       *
0508       * @throws BadMethodCallException When this ContainerBuilder is frozen
0509       */
0510      public function merge(ContainerBuilder $container)
0511      {
0512          if ($this->isFrozen()) {
0513              throw new BadMethodCallException('Cannot merge on a frozen container.');
0514          }
0515   
0516          $this->addDefinitions($container->getDefinitions());
0517          $this->addAliases($container->getAliases());
0518          $this->getParameterBag()->add($container->getParameterBag()->all());
0519   
0520          if ($this->trackResources) {
0521              foreach ($container->getResources() as $resource) {
0522                  $this->addResource($resource);
0523              }
0524          }
0525   
0526          foreach ($this->extensions as $name => $extension) {
0527              if (!isset($this->extensionConfigs[$name])) {
0528                  $this->extensionConfigs[$name] = array();
0529              }
0530   
0531              $this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
0532          }
0533      }
0534   
0535      /**
0536       * Returns the configuration array for the given extension.
0537       *
0538       * @param string $name The name of the extension
0539       *
0540       * @return array An array of configuration
0541       */
0542      public function getExtensionConfig($name)
0543      {
0544          if (!isset($this->extensionConfigs[$name])) {
0545              $this->extensionConfigs[$name] = array();
0546          }
0547   
0548          return $this->extensionConfigs[$name];
0549      }
0550   
0551      /**
0552       * Prepends a config array to the configs of the given extension.
0553       *
0554       * @param string $name   The name of the extension
0555       * @param array  $config The config to set
0556       */
0557      public function prependExtensionConfig($name, array $config)
0558      {
0559          if (!isset($this->extensionConfigs[$name])) {
0560              $this->extensionConfigs[$name] = array();
0561          }
0562   
0563          array_unshift($this->extensionConfigs[$name], $config);
0564      }
0565   
0566      /**
0567       * Compiles the container.
0568       *
0569       * This method passes the container to compiler
0570       * passes whose job is to manipulate and optimize
0571       * the container.
0572       *
0573       * The main compiler passes roughly do four things:
0574       *
0575       *  * The extension configurations are merged;
0576       *  * Parameter values are resolved;
0577       *  * The parameter bag is frozen;
0578       *  * Extension loading is disabled.
0579       */
0580      public function compile()
0581      {
0582          $compiler = $this->getCompiler();
0583   
0584          if ($this->trackResources) {
0585              foreach ($compiler->getPassConfig()->getPasses() as $pass) {
0586                  $this->addObjectResource($pass);
0587              }
0588          }
0589   
0590          $compiler->compile($this);
0591   
0592          if ($this->trackResources) {
0593              foreach ($this->definitions as $definition) {
0594                  if ($definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
0595                      $this->addClassResource(new \ReflectionClass($class));
0596                  }
0597              }
0598          }
0599   
0600          $this->extensionConfigs = array();
0601   
0602          parent::compile();
0603      }
0604   
0605      /**
0606       * Gets all service ids.
0607       *
0608       * @return array An array of all defined service ids
0609       */
0610      public function getServiceIds()
0611      {
0612          return array_unique(array_merge(array_keys($this->getDefinitions()), array_keys($this->aliasDefinitions), parent::getServiceIds()));
0613      }
0614   
0615      /**
0616       * Adds the service aliases.
0617       *
0618       * @param array $aliases An array of aliases
0619       */
0620      public function addAliases(array $aliases)
0621      {
0622          foreach ($aliases as $alias => $id) {
0623              $this->setAlias($alias, $id);
0624          }
0625      }
0626   
0627      /**
0628       * Sets the service aliases.
0629       *
0630       * @param array $aliases An array of aliases
0631       */
0632      public function setAliases(array $aliases)
0633      {
0634          $this->aliasDefinitions = array();
0635          $this->addAliases($aliases);
0636      }
0637   
0638      /**
0639       * Sets an alias for an existing service.
0640       *
0641       * @param string       $alias The alias to create
0642       * @param string|Alias $id    The service to alias
0643       *
0644       * @throws InvalidArgumentException if the id is not a string or an Alias
0645       * @throws InvalidArgumentException if the alias is for itself
0646       */
0647      public function setAlias($alias, $id)
0648      {
0649          $alias = strtolower($alias);
0650   
0651          if (is_string($id)) {
0652              $id = new Alias($id);
0653          } elseif (!$id instanceof Alias) {
0654              throw new InvalidArgumentException('$id must be a string, or an Alias object.');
0655          }
0656   
0657          if ($alias === (string) $id) {
0658              throw new InvalidArgumentException(sprintf('An alias can not reference itself, got a circular reference on "%s".', $alias));
0659          }
0660   
0661          unset($this->definitions[$alias]);
0662   
0663          $this->aliasDefinitions[$alias] = $id;
0664      }
0665   
0666      /**
0667       * Removes an alias.
0668       *
0669       * @param string $alias The alias to remove
0670       */
0671      public function removeAlias($alias)
0672      {
0673          unset($this->aliasDefinitions[strtolower($alias)]);
0674      }
0675   
0676      /**
0677       * Returns true if an alias exists under the given identifier.
0678       *
0679       * @param string $id The service identifier
0680       *
0681       * @return bool true if the alias exists, false otherwise
0682       */
0683      public function hasAlias($id)
0684      {
0685          return isset($this->aliasDefinitions[strtolower($id)]);
0686      }
0687   
0688      /**
0689       * Gets all defined aliases.
0690       *
0691       * @return Alias[] An array of aliases
0692       */
0693      public function getAliases()
0694      {
0695          return $this->aliasDefinitions;
0696      }
0697   
0698      /**
0699       * Gets an alias.
0700       *
0701       * @param string $id The service identifier
0702       *
0703       * @return Alias An Alias instance
0704       *
0705       * @throws InvalidArgumentException if the alias does not exist
0706       */
0707      public function getAlias($id)
0708      {
0709          $id = strtolower($id);
0710   
0711          if (!isset($this->aliasDefinitions[$id])) {
0712              throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id));
0713          }
0714   
0715          return $this->aliasDefinitions[$id];
0716      }
0717   
0718      /**
0719       * Registers a service definition.
0720       *
0721       * This methods allows for simple registration of service definition
0722       * with a fluid interface.
0723       *
0724       * @param string $id    The service identifier
0725       * @param string $class The service class
0726       *
0727       * @return Definition A Definition instance
0728       */
0729      public function register($id, $class = null)
0730      {
0731          return $this->setDefinition($id, new Definition($class));
0732      }
0733   
0734      /**
0735       * Adds the service definitions.
0736       *
0737       * @param Definition[] $definitions An array of service definitions
0738       */
0739      public function addDefinitions(array $definitions)
0740      {
0741          foreach ($definitions as $id => $definition) {
0742              $this->setDefinition($id, $definition);
0743          }
0744      }
0745   
0746      /**
0747       * Sets the service definitions.
0748       *
0749       * @param Definition[] $definitions An array of service definitions
0750       */
0751      public function setDefinitions(array $definitions)
0752      {
0753          $this->definitions = array();
0754          $this->addDefinitions($definitions);
0755      }
0756   
0757      /**
0758       * Gets all service definitions.
0759       *
0760       * @return Definition[] An array of Definition instances
0761       */
0762      public function getDefinitions()
0763      {
0764          return $this->definitions;
0765      }
0766   
0767      /**
0768       * Sets a service definition.
0769       *
0770       * @param string     $id         The service identifier
0771       * @param Definition $definition A Definition instance
0772       *
0773       * @return Definition the service definition
0774       *
0775       * @throws BadMethodCallException When this ContainerBuilder is frozen
0776       */
0777      public function setDefinition($id, Definition $definition)
0778      {
0779          if ($this->isFrozen()) {
0780              throw new BadMethodCallException('Adding definition to a frozen container is not allowed');
0781          }
0782   
0783          $id = strtolower($id);
0784   
0785          unset($this->aliasDefinitions[$id]);
0786   
0787          return $this->definitions[$id] = $definition;
0788      }
0789   
0790      /**
0791       * Returns true if a service definition exists under the given identifier.
0792       *
0793       * @param string $id The service identifier
0794       *
0795       * @return bool true if the service definition exists, false otherwise
0796       */
0797      public function hasDefinition($id)
0798      {
0799          return array_key_exists(strtolower($id), $this->definitions);
0800      }
0801   
0802      /**
0803       * Gets a service definition.
0804       *
0805       * @param string $id The service identifier
0806       *
0807       * @return Definition A Definition instance
0808       *
0809       * @throws ServiceNotFoundException if the service definition does not exist
0810       */
0811      public function getDefinition($id)
0812      {
0813          $id = strtolower($id);
0814   
0815          if (!array_key_exists($id, $this->definitions)) {
0816              throw new ServiceNotFoundException($id);
0817          }
0818   
0819          return $this->definitions[$id];
0820      }
0821   
0822      /**
0823       * Gets a service definition by id or alias.
0824       *
0825       * The method "unaliases" recursively to return a Definition instance.
0826       *
0827       * @param string $id The service identifier or alias
0828       *
0829       * @return Definition A Definition instance
0830       *
0831       * @throws ServiceNotFoundException if the service definition does not exist
0832       */
0833      public function findDefinition($id)
0834      {
0835          $id = strtolower($id);
0836   
0837          while (isset($this->aliasDefinitions[$id])) {
0838              $id = (string) $this->aliasDefinitions[$id];
0839          }
0840   
0841          return $this->getDefinition($id);
0842      }
0843   
0844      /**
0845       * Creates a service for a service definition.
0846       *
0847       * @param Definition $definition A service definition instance
0848       * @param string     $id         The service identifier
0849       * @param bool       $tryProxy   Whether to try proxying the service with a lazy proxy
0850       *
0851       * @return object The service described by the service definition
0852       *
0853       * @throws RuntimeException         When the scope is inactive
0854       * @throws RuntimeException         When the factory definition is incomplete
0855       * @throws RuntimeException         When the service is a synthetic service
0856       * @throws InvalidArgumentException When configure callable is not callable
0857       *
0858       * @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code
0859       */
0860      public function createService(Definition $definition, $id, $tryProxy = true)
0861      {
0862          if ('Symfony\Component\DependencyInjection\Definition' !== get_class($definition)) {
0863              throw new RuntimeException(sprintf('Constructing service "%s" from a %s is not supported at build time.', $id, get_class($definition)));
0864          }
0865   
0866          if ($definition->isSynthetic()) {
0867              throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
0868          }
0869   
0870          if ($definition->isDeprecated()) {
0871              @trigger_error($definition->getDeprecationMessage($id), E_USER_DEPRECATED);
0872          }
0873   
0874          if ($tryProxy && $definition->isLazy()) {
0875              $container = $this;
0876   
0877              $proxy = $this
0878                  ->getProxyInstantiator()
0879                  ->instantiateProxy(
0880                      $container,
0881                      $definition,
0882                      $id, function () use ($definition, $id, $container) {
0883                          return $container->createService($definition, $id, false);
0884                      }
0885                  );
0886              $this->shareService($definition, $proxy, $id);
0887   
0888              return $proxy;
0889          }
0890   
0891          $parameterBag = $this->getParameterBag();
0892   
0893          if (null !== $definition->getFile()) {
0894              require_once $parameterBag->resolveValue($definition->getFile());
0895          }
0896   
0897          $arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())));
0898   
0899          if (null !== $factory = $definition->getFactory()) {
0900              if (is_array($factory)) {
0901                  $factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]);
0902              } elseif (!is_string($factory)) {
0903                  throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
0904              }
0905   
0906              $service = call_user_func_array($factory, $arguments);
0907   
0908              if (!$definition->isDeprecated() && is_array($factory) && is_string($factory[0])) {
0909                  $r = new \ReflectionClass($factory[0]);
0910   
0911                  if (0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
0912                      @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);
0913                  }
0914              }
0915          } elseif (null !== $definition->getFactoryMethod(false)) {
0916              if (null !== $definition->getFactoryClass(false)) {
0917                  $factory = $parameterBag->resolveValue($definition->getFactoryClass(false));
0918              } elseif (null !== $definition->getFactoryService(false)) {
0919                  $factory = $this->get($parameterBag->resolveValue($definition->getFactoryService(false)));
0920              } else {
0921                  throw new RuntimeException(sprintf('Cannot create service "%s" from factory method without a factory service or factory class.', $id));
0922              }
0923   
0924              $service = call_user_func_array(array($factory, $definition->getFactoryMethod(false)), $arguments);
0925          } else {
0926              $r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
0927   
0928              $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
0929   
0930              if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
0931                  @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);
0932              }
0933          }
0934   
0935          if ($tryProxy || !$definition->isLazy()) {
0936              // share only if proxying failed, or if not a proxy
0937              $this->shareService($definition, $service, $id);
0938          }
0939   
0940          foreach ($definition->getMethodCalls() as $call) {
0941              $this->callMethod($service, $call);
0942          }
0943   
0944          $properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())));
0945          foreach ($properties as $name => $value) {
0946              $service->$name = $value;
0947          }
0948   
0949          if ($callable = $definition->getConfigurator()) {
0950              if (is_array($callable)) {
0951                  $callable[0] = $parameterBag->resolveValue($callable[0]);
0952   
0953                  if ($callable[0] instanceof Reference) {
0954                      $callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior());
0955                  } elseif ($callable[0] instanceof Definition) {
0956                      $callable[0] = $this->createService($callable[0], null);
0957                  }
0958              }
0959   
0960              if (!is_callable($callable)) {
0961                  throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service)));
0962              }
0963   
0964              call_user_func($callable, $service);
0965          }
0966   
0967          return $service;
0968      }
0969   
0970      /**
0971       * Replaces service references by the real service instance and evaluates expressions.
0972       *
0973       * @param mixed $value A value
0974       *
0975       * @return mixed The same value with all service references replaced by
0976       *               the real service instances and all expressions evaluated
0977       */
0978      public function resolveServices($value)
0979      {
0980          if (is_array($value)) {
0981              foreach ($value as $k => $v) {
0982                  $value[$k] = $this->resolveServices($v);
0983              }
0984          } elseif ($value instanceof Reference) {
0985              $value = $this->get((string) $value, $value->getInvalidBehavior());
0986          } elseif ($value instanceof Definition) {
0987              $value = $this->createService($value, null);
0988          } elseif ($value instanceof Expression) {
0989              $value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this));
0990          }
0991   
0992          return $value;
0993      }
0994   
0995      /**
0996       * Returns service ids for a given tag.
0997       *
0998       * Example:
0999       *
1000       * $container->register('foo')->addTag('my.tag', array('hello' => 'world'));
1001       *
1002       * $serviceIds = $container->findTaggedServiceIds('my.tag');
1003       * foreach ($serviceIds as $serviceId => $tags) {
1004       *     foreach ($tags as $tag) {
1005       *         echo $tag['hello'];
1006       *     }
1007       * }
1008       *
1009       * @param string $name The tag name
1010       *
1011       * @return array An array of tags with the tagged service as key, holding a list of attribute arrays
1012       */
1013      public function findTaggedServiceIds($name)
1014      {
1015          $this->usedTags[] = $name;
1016          $tags = array();
1017          foreach ($this->getDefinitions() as $id => $definition) {
1018              if ($definition->hasTag($name)) {
1019                  $tags[$id] = $definition->getTag($name);
1020              }
1021          }
1022   
1023          return $tags;
1024      }
1025   
1026      /**
1027       * Returns all tags the defined services use.
1028       *
1029       * @return array An array of tags
1030       */
1031      public function findTags()
1032      {
1033          $tags = array();
1034          foreach ($this->getDefinitions() as $id => $definition) {
1035              $tags = array_merge(array_keys($definition->getTags()), $tags);
1036          }
1037   
1038          return array_unique($tags);
1039      }
1040   
1041      /**
1042       * Returns all tags not queried by findTaggedServiceIds.
1043       *
1044       * @return string[] An array of tags
1045       */
1046      public function findUnusedTags()
1047      {
1048          return array_values(array_diff($this->findTags(), $this->usedTags));
1049      }
1050   
1051      public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
1052      {
1053          $this->expressionLanguageProviders[] = $provider;
1054      }
1055   
1056      /**
1057       * @return ExpressionFunctionProviderInterface[]
1058       */
1059      public function getExpressionLanguageProviders()
1060      {
1061          return $this->expressionLanguageProviders;
1062      }
1063   
1064      /**
1065       * Returns the Service Conditionals.
1066       *
1067       * @param mixed $value An array of conditionals to return
1068       *
1069       * @return array An array of Service conditionals
1070       */
1071      public static function getServiceConditionals($value)
1072      {
1073          $services = array();
1074   
1075          if (is_array($value)) {
1076              foreach ($value as $v) {
1077                  $services = array_unique(array_merge($services, self::getServiceConditionals($v)));
1078              }
1079          } elseif ($value instanceof Reference && $value->getInvalidBehavior() === ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
1080              $services[] = (string) $value;
1081          }
1082   
1083          return $services;
1084      }
1085   
1086      /**
1087       * Retrieves the currently set proxy instantiator or instantiates one.
1088       *
1089       * @return InstantiatorInterface
1090       */
1091      private function getProxyInstantiator()
1092      {
1093          if (!$this->proxyInstantiator) {
1094              $this->proxyInstantiator = new RealServiceInstantiator();
1095          }
1096   
1097          return $this->proxyInstantiator;
1098      }
1099   
1100      /**
1101       * Synchronizes a service change.
1102       *
1103       * This method updates all services that depend on the given
1104       * service by calling all methods referencing it.
1105       *
1106       * @param string $id A service id
1107       *
1108       * @deprecated since version 2.7, will be removed in 3.0.
1109       */
1110      private function synchronize($id)
1111      {
1112          if ('request' !== $id) {
1113              @trigger_error('The '.__METHOD__.' method is deprecated in version 2.7 and will be removed in version 3.0.', E_USER_DEPRECATED);
1114          }
1115   
1116          foreach ($this->definitions as $definitionId => $definition) {
1117              // only check initialized services
1118              if (!$this->initialized($definitionId)) {
1119                  continue;
1120              }
1121   
1122              foreach ($definition->getMethodCalls() as $call) {
1123                  foreach ($call[1] as $argument) {
1124                      if ($argument instanceof Reference && $id == (string) $argument) {
1125                          $this->callMethod($this->get($definitionId), $call);
1126                      }
1127                  }
1128              }
1129          }
1130      }
1131   
1132      private function callMethod($service, $call)
1133      {
1134          $services = self::getServiceConditionals($call[1]);
1135   
1136          foreach ($services as $s) {
1137              if (!$this->has($s)) {
1138                  return;
1139              }
1140          }
1141   
1142          call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1]))));
1143      }
1144   
1145      /**
1146       * Shares a given service in the container.
1147       *
1148       * @param Definition $definition
1149       * @param mixed      $service
1150       * @param string     $id
1151       *
1152       * @throws InactiveScopeException
1153       */
1154      private function shareService(Definition $definition, $service, $id)
1155      {
1156          if ($definition->isShared() && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
1157              if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
1158                  throw new InactiveScopeException($id, $scope);
1159              }
1160   
1161              $this->services[$lowerId = strtolower($id)] = $service;
1162   
1163              if (self::SCOPE_CONTAINER !== $scope) {
1164                  $this->scopedServices[$scope][$lowerId] = $service;
1165              }
1166          }
1167      }
1168   
1169      private function getExpressionLanguage()
1170      {
1171          if (null === $this->expressionLanguage) {
1172              if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
1173                  throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
1174              }
1175              $this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders);
1176          }
1177   
1178          return $this->expressionLanguage;
1179      }
1180  }
1181