[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

/vendor/symfony/dependency-injection/ -> Container.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the Symfony package.
   5   *
   6   * (c) Fabien Potencier <fabien@symfony.com>
   7   *
   8   * For the full copyright and license information, please view the LICENSE
   9   * file that was distributed with this source code.
  10   */
  11  
  12  namespace Symfony\Component\DependencyInjection;
  13  
  14  use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
  15  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  16  use Symfony\Component\DependencyInjection\Exception\LogicException;
  17  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  18  use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
  19  use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  20  use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
  21  use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
  22  use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  23  
  24  /**
  25   * Container is a dependency injection container.
  26   *
  27   * It gives access to object instances (services).
  28   *
  29   * Services and parameters are simple key/pair stores.
  30   *
  31   * Parameter and service keys are case insensitive.
  32   *
  33   * A service can also be defined by creating a method named
  34   * getXXXService(), where XXX is the camelized version of the id:
  35   *
  36   *  * request -> getRequestService()
  37   *  * mysql_session_storage -> getMysqlSessionStorageService()
  38   *  * symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()
  39   *
  40   * The container can have three possible behaviors when a service does not exist:
  41   *
  42   *  * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception (the default)
  43   *  * NULL_ON_INVALID_REFERENCE:      Returns null
  44   *  * IGNORE_ON_INVALID_REFERENCE:    Ignores the wrapping command asking for the reference
  45   *                                    (for instance, ignore a setter if the service does not exist)
  46   *
  47   * @author Fabien Potencier <fabien@symfony.com>
  48   * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  49   */
  50  class Container implements IntrospectableContainerInterface, ResettableContainerInterface
  51  {
  52      protected $parameterBag;
  53      protected $services = array();
  54      protected $methodMap = array();
  55      protected $aliases = array();
  56      protected $scopes = array();
  57      protected $scopeChildren = array();
  58      protected $scopedServices = array();
  59      protected $scopeStacks = array();
  60      protected $loading = array();
  61  
  62      private $underscoreMap = array('_' => '', '.' => '_', '\\' => '_');
  63  
  64      public function __construct(ParameterBagInterface $parameterBag = null)
  65      {
  66          $this->parameterBag = $parameterBag ?: new ParameterBag();
  67      }
  68  
  69      /**
  70       * Compiles the container.
  71       *
  72       * This method does two things:
  73       *
  74       *  * Parameter values are resolved;
  75       *  * The parameter bag is frozen.
  76       */
  77      public function compile()
  78      {
  79          $this->parameterBag->resolve();
  80  
  81          $this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
  82      }
  83  
  84      /**
  85       * Returns true if the container parameter bag are frozen.
  86       *
  87       * @return bool true if the container parameter bag are frozen, false otherwise
  88       */
  89      public function isFrozen()
  90      {
  91          return $this->parameterBag instanceof FrozenParameterBag;
  92      }
  93  
  94      /**
  95       * Gets the service container parameter bag.
  96       *
  97       * @return ParameterBagInterface A ParameterBagInterface instance
  98       */
  99      public function getParameterBag()
 100      {
 101          return $this->parameterBag;
 102      }
 103  
 104      /**
 105       * Gets a parameter.
 106       *
 107       * @param string $name The parameter name
 108       *
 109       * @return mixed The parameter value
 110       *
 111       * @throws InvalidArgumentException if the parameter is not defined
 112       */
 113      public function getParameter($name)
 114      {
 115          return $this->parameterBag->get($name);
 116      }
 117  
 118      /**
 119       * Checks if a parameter exists.
 120       *
 121       * @param string $name The parameter name
 122       *
 123       * @return bool The presence of parameter in container
 124       */
 125      public function hasParameter($name)
 126      {
 127          return $this->parameterBag->has($name);
 128      }
 129  
 130      /**
 131       * Sets a parameter.
 132       *
 133       * @param string $name  The parameter name
 134       * @param mixed  $value The parameter value
 135       */
 136      public function setParameter($name, $value)
 137      {
 138          $this->parameterBag->set($name, $value);
 139      }
 140  
 141      /**
 142       * Sets a service.
 143       *
 144       * Setting a service to null resets the service: has() returns false and get()
 145       * behaves in the same way as if the service was never created.
 146       *
 147       * Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
 148       *
 149       * @param string $id      The service identifier
 150       * @param object $service The service instance
 151       * @param string $scope   The scope of the service
 152       *
 153       * @throws RuntimeException         When trying to set a service in an inactive scope
 154       * @throws InvalidArgumentException When trying to set a service in the prototype scope
 155       */
 156      public function set($id, $service, $scope = self::SCOPE_CONTAINER)
 157      {
 158          if (!\in_array($scope, array('container', 'request')) || ('request' === $scope && 'request' !== $id)) {
 159              @trigger_error('The concept of container scopes is deprecated since Symfony 2.8 and will be removed in 3.0. Omit the third parameter.', E_USER_DEPRECATED);
 160          }
 161  
 162          if (self::SCOPE_PROTOTYPE === $scope) {
 163              throw new InvalidArgumentException(sprintf('You cannot set service "%s" of scope "prototype".', $id));
 164          }
 165  
 166          $id = strtolower($id);
 167  
 168          if ('service_container' === $id) {
 169              // BC: 'service_container' is no longer a self-reference but always
 170              // $this, so ignore this call.
 171              // @todo Throw InvalidArgumentException in next major release.
 172              return;
 173          }
 174          if (self::SCOPE_CONTAINER !== $scope) {
 175              if (!isset($this->scopedServices[$scope])) {
 176                  throw new RuntimeException(sprintf('You cannot set service "%s" of inactive scope.', $id));
 177              }
 178  
 179              $this->scopedServices[$scope][$id] = $service;
 180          }
 181  
 182          if (isset($this->aliases[$id])) {
 183              unset($this->aliases[$id]);
 184          }
 185  
 186          $this->services[$id] = $service;
 187  
 188          if (method_exists($this, $method = 'synchronize'.strtr($id, $this->underscoreMap).'Service')) {
 189              $this->$method();
 190          }
 191  
 192          if (null === $service) {
 193              if (self::SCOPE_CONTAINER !== $scope) {
 194                  unset($this->scopedServices[$scope][$id]);
 195              }
 196  
 197              unset($this->services[$id]);
 198          }
 199      }
 200  
 201      /**
 202       * Returns true if the given service is defined.
 203       *
 204       * @param string $id The service identifier
 205       *
 206       * @return bool true if the service is defined, false otherwise
 207       */
 208      public function has($id)
 209      {
 210          for ($i = 2;;) {
 211              if ('service_container' === $id
 212                  || isset($this->aliases[$id])
 213                  || isset($this->services[$id])
 214                  || array_key_exists($id, $this->services)
 215              ) {
 216                  return true;
 217              }
 218              if (--$i && $id !== $lcId = strtolower($id)) {
 219                  $id = $lcId;
 220              } else {
 221                  return method_exists($this, 'get'.strtr($id, $this->underscoreMap).'Service');
 222              }
 223          }
 224      }
 225  
 226      /**
 227       * Gets a service.
 228       *
 229       * If a service is defined both through a set() method and
 230       * with a get{$id}Service() method, the former has always precedence.
 231       *
 232       * @param string $id              The service identifier
 233       * @param int    $invalidBehavior The behavior when the service does not exist
 234       *
 235       * @return object The associated service
 236       *
 237       * @throws ServiceCircularReferenceException When a circular reference is detected
 238       * @throws ServiceNotFoundException          When the service is not defined
 239       * @throws \Exception                        if an exception has been thrown when the service has been resolved
 240       *
 241       * @see Reference
 242       */
 243      public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE)
 244      {
 245          // Attempt to retrieve the service by checking first aliases then
 246          // available services. Service IDs are case insensitive, however since
 247          // this method can be called thousands of times during a request, avoid
 248          // calling strtolower() unless necessary.
 249          for ($i = 2;;) {
 250              if (isset($this->aliases[$id])) {
 251                  $id = $this->aliases[$id];
 252              }
 253              // Re-use shared service instance if it exists.
 254              if (isset($this->services[$id]) || array_key_exists($id, $this->services)) {
 255                  return $this->services[$id];
 256              }
 257              if ('service_container' === $id) {
 258                  return $this;
 259              }
 260  
 261              if (isset($this->loading[$id])) {
 262                  throw new ServiceCircularReferenceException($id, array_keys($this->loading));
 263              }
 264  
 265              if (isset($this->methodMap[$id])) {
 266                  $method = $this->methodMap[$id];
 267              } elseif (--$i && $id !== $lcId = strtolower($id)) {
 268                  $id = $lcId;
 269                  continue;
 270              } elseif (method_exists($this, $method = 'get'.strtr($id, $this->underscoreMap).'Service')) {
 271                  // $method is set to the right value, proceed
 272              } else {
 273                  if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
 274                      if (!$id) {
 275                          throw new ServiceNotFoundException($id);
 276                      }
 277  
 278                      $alternatives = array();
 279                      foreach ($this->getServiceIds() as $knownId) {
 280                          $lev = levenshtein($id, $knownId);
 281                          if ($lev <= \strlen($id) / 3 || false !== strpos($knownId, $id)) {
 282                              $alternatives[] = $knownId;
 283                          }
 284                      }
 285  
 286                      throw new ServiceNotFoundException($id, null, null, $alternatives);
 287                  }
 288  
 289                  return;
 290              }
 291  
 292              $this->loading[$id] = true;
 293  
 294              try {
 295                  $service = $this->$method();
 296              } catch (\Exception $e) {
 297                  unset($this->loading[$id]);
 298                  unset($this->services[$id]);
 299  
 300                  if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
 301                      return;
 302                  }
 303  
 304                  throw $e;
 305              } catch (\Throwable $e) {
 306                  unset($this->loading[$id]);
 307                  unset($this->services[$id]);
 308  
 309                  throw $e;
 310              }
 311  
 312              unset($this->loading[$id]);
 313  
 314              return $service;
 315          }
 316      }
 317  
 318      /**
 319       * Returns true if the given service has actually been initialized.
 320       *
 321       * @param string $id The service identifier
 322       *
 323       * @return bool true if service has already been initialized, false otherwise
 324       */
 325      public function initialized($id)
 326      {
 327          $id = strtolower($id);
 328  
 329          if (isset($this->aliases[$id])) {
 330              $id = $this->aliases[$id];
 331          }
 332  
 333          if ('service_container' === $id) {
 334              // BC: 'service_container' was a synthetic service previously.
 335              // @todo Change to false in next major release.
 336              return true;
 337          }
 338  
 339          return isset($this->services[$id]) || array_key_exists($id, $this->services);
 340      }
 341  
 342      /**
 343       * {@inheritdoc}
 344       */
 345      public function reset()
 346      {
 347          if (!empty($this->scopedServices)) {
 348              throw new LogicException('Resetting the container is not allowed when a scope is active.');
 349          }
 350  
 351          $this->services = array();
 352      }
 353  
 354      /**
 355       * Gets all service ids.
 356       *
 357       * @return array An array of all defined service ids
 358       */
 359      public function getServiceIds()
 360      {
 361          $ids = array();
 362          foreach (get_class_methods($this) as $method) {
 363              if (preg_match('/^get(.+)Service$/', $method, $match)) {
 364                  $ids[] = self::underscore($match[1]);
 365              }
 366          }
 367          $ids[] = 'service_container';
 368  
 369          return array_unique(array_merge($ids, array_keys($this->services)));
 370      }
 371  
 372      /**
 373       * This is called when you enter a scope.
 374       *
 375       * @param string $name
 376       *
 377       * @throws RuntimeException         When the parent scope is inactive
 378       * @throws InvalidArgumentException When the scope does not exist
 379       *
 380       * @deprecated since version 2.8, to be removed in 3.0.
 381       */
 382      public function enterScope($name)
 383      {
 384          if ('request' !== $name) {
 385              @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
 386          }
 387  
 388          if (!isset($this->scopes[$name])) {
 389              throw new InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name));
 390          }
 391  
 392          if (self::SCOPE_CONTAINER !== $this->scopes[$name] && !isset($this->scopedServices[$this->scopes[$name]])) {
 393              throw new RuntimeException(sprintf('The parent scope "%s" must be active when entering this scope.', $this->scopes[$name]));
 394          }
 395  
 396          // check if a scope of this name is already active, if so we need to
 397          // remove all services of this scope, and those of any of its child
 398          // scopes from the global services map
 399          if (isset($this->scopedServices[$name])) {
 400              $services = array($this->services, $name => $this->scopedServices[$name]);
 401              unset($this->scopedServices[$name]);
 402  
 403              foreach ($this->scopeChildren[$name] as $child) {
 404                  if (isset($this->scopedServices[$child])) {
 405                      $services[$child] = $this->scopedServices[$child];
 406                      unset($this->scopedServices[$child]);
 407                  }
 408              }
 409  
 410              // update global map
 411              $this->services = \call_user_func_array('array_diff_key', $services);
 412              array_shift($services);
 413  
 414              // add stack entry for this scope so we can restore the removed services later
 415              if (!isset($this->scopeStacks[$name])) {
 416                  $this->scopeStacks[$name] = new \SplStack();
 417              }
 418              $this->scopeStacks[$name]->push($services);
 419          }
 420  
 421          $this->scopedServices[$name] = array();
 422      }
 423  
 424      /**
 425       * This is called to leave the current scope, and move back to the parent
 426       * scope.
 427       *
 428       * @param string $name The name of the scope to leave
 429       *
 430       * @throws InvalidArgumentException if the scope is not active
 431       *
 432       * @deprecated since version 2.8, to be removed in 3.0.
 433       */
 434      public function leaveScope($name)
 435      {
 436          if ('request' !== $name) {
 437              @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
 438          }
 439  
 440          if (!isset($this->scopedServices[$name])) {
 441              throw new InvalidArgumentException(sprintf('The scope "%s" is not active.', $name));
 442          }
 443  
 444          // remove all services of this scope, or any of its child scopes from
 445          // the global service map
 446          $services = array($this->services, $this->scopedServices[$name]);
 447          unset($this->scopedServices[$name]);
 448  
 449          foreach ($this->scopeChildren[$name] as $child) {
 450              if (isset($this->scopedServices[$child])) {
 451                  $services[] = $this->scopedServices[$child];
 452                  unset($this->scopedServices[$child]);
 453              }
 454          }
 455  
 456          // update global map
 457          $this->services = \call_user_func_array('array_diff_key', $services);
 458  
 459          // check if we need to restore services of a previous scope of this type
 460          if (isset($this->scopeStacks[$name]) && \count($this->scopeStacks[$name]) > 0) {
 461              $services = $this->scopeStacks[$name]->pop();
 462              $this->scopedServices += $services;
 463  
 464              if ($this->scopeStacks[$name]->isEmpty()) {
 465                  unset($this->scopeStacks[$name]);
 466              }
 467  
 468              foreach ($services as $array) {
 469                  foreach ($array as $id => $service) {
 470                      $this->set($id, $service, $name);
 471                  }
 472              }
 473          }
 474      }
 475  
 476      /**
 477       * Adds a scope to the container.
 478       *
 479       * @throws InvalidArgumentException
 480       *
 481       * @deprecated since version 2.8, to be removed in 3.0.
 482       */
 483      public function addScope(ScopeInterface $scope)
 484      {
 485          $name = $scope->getName();
 486          $parentScope = $scope->getParentName();
 487  
 488          if ('request' !== $name) {
 489              @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
 490          }
 491          if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) {
 492              throw new InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name));
 493          }
 494          if (isset($this->scopes[$name])) {
 495              throw new InvalidArgumentException(sprintf('A scope with name "%s" already exists.', $name));
 496          }
 497          if (self::SCOPE_CONTAINER !== $parentScope && !isset($this->scopes[$parentScope])) {
 498              throw new InvalidArgumentException(sprintf('The parent scope "%s" does not exist, or is invalid.', $parentScope));
 499          }
 500  
 501          $this->scopes[$name] = $parentScope;
 502          $this->scopeChildren[$name] = array();
 503  
 504          // normalize the child relations
 505          while (self::SCOPE_CONTAINER !== $parentScope) {
 506              $this->scopeChildren[$parentScope][] = $name;
 507              $parentScope = $this->scopes[$parentScope];
 508          }
 509      }
 510  
 511      /**
 512       * Returns whether this container has a certain scope.
 513       *
 514       * @param string $name The name of the scope
 515       *
 516       * @return bool
 517       *
 518       * @deprecated since version 2.8, to be removed in 3.0.
 519       */
 520      public function hasScope($name)
 521      {
 522          if ('request' !== $name) {
 523              @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
 524          }
 525  
 526          return isset($this->scopes[$name]);
 527      }
 528  
 529      /**
 530       * Returns whether this scope is currently active.
 531       *
 532       * This does not actually check if the passed scope actually exists.
 533       *
 534       * @param string $name
 535       *
 536       * @return bool
 537       *
 538       * @deprecated since version 2.8, to be removed in 3.0.
 539       */
 540      public function isScopeActive($name)
 541      {
 542          @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
 543  
 544          return isset($this->scopedServices[$name]);
 545      }
 546  
 547      /**
 548       * Camelizes a string.
 549       *
 550       * @param string $id A string to camelize
 551       *
 552       * @return string The camelized string
 553       */
 554      public static function camelize($id)
 555      {
 556          return strtr(ucwords(strtr($id, array('_' => ' ', '.' => '_ ', '\\' => '_ '))), array(' ' => ''));
 557      }
 558  
 559      /**
 560       * A string to underscore.
 561       *
 562       * @param string $id The string to underscore
 563       *
 564       * @return string The underscored string
 565       */
 566      public static function underscore($id)
 567      {
 568          return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), str_replace('_', '.', $id)));
 569      }
 570  
 571      private function __clone()
 572      {
 573      }
 574  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1