[ Index ]

PHP Cross Reference of phpBB-3.3.5-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\EnvNotFoundException;
  15  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  16  use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
  17  use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
  18  use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  19  use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
  20  use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
  21  use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  22  
  23  /**
  24   * Container is a dependency injection container.
  25   *
  26   * It gives access to object instances (services).
  27   * Services and parameters are simple key/pair stores.
  28   * The container can have four possible behaviors when a service
  29   * does not exist (or is not initialized for the last case):
  30   *
  31   *  * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception (the default)
  32   *  * NULL_ON_INVALID_REFERENCE:      Returns null
  33   *  * IGNORE_ON_INVALID_REFERENCE:    Ignores the wrapping command asking for the reference
  34   *                                    (for instance, ignore a setter if the service does not exist)
  35   *  * IGNORE_ON_UNINITIALIZED_REFERENCE: Ignores/returns null for uninitialized services or invalid references
  36   *
  37   * @author Fabien Potencier <fabien@symfony.com>
  38   * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  39   */
  40  class Container implements ResettableContainerInterface
  41  {
  42      protected $parameterBag;
  43      protected $services = [];
  44      protected $fileMap = [];
  45      protected $methodMap = [];
  46      protected $aliases = [];
  47      protected $loading = [];
  48      protected $resolving = [];
  49      protected $syntheticIds = [];
  50  
  51      /**
  52       * @internal
  53       */
  54      protected $privates = [];
  55  
  56      /**
  57       * @internal
  58       */
  59      protected $normalizedIds = [];
  60  
  61      private $underscoreMap = ['_' => '', '.' => '_', '\\' => '_'];
  62      private $envCache = [];
  63      private $compiled = false;
  64      private $getEnv;
  65  
  66      public function __construct(ParameterBagInterface $parameterBag = null)
  67      {
  68          $this->parameterBag = $parameterBag ?: new EnvPlaceholderParameterBag();
  69      }
  70  
  71      /**
  72       * Compiles the container.
  73       *
  74       * This method does two things:
  75       *
  76       *  * Parameter values are resolved;
  77       *  * The parameter bag is frozen.
  78       */
  79      public function compile()
  80      {
  81          $this->parameterBag->resolve();
  82  
  83          $this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
  84  
  85          $this->compiled = true;
  86      }
  87  
  88      /**
  89       * Returns true if the container is compiled.
  90       *
  91       * @return bool
  92       */
  93      public function isCompiled()
  94      {
  95          return $this->compiled;
  96      }
  97  
  98      /**
  99       * Returns true if the container parameter bag are frozen.
 100       *
 101       * @deprecated since version 3.3, to be removed in 4.0.
 102       *
 103       * @return bool true if the container parameter bag are frozen, false otherwise
 104       */
 105      public function isFrozen()
 106      {
 107          @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), \E_USER_DEPRECATED);
 108  
 109          return $this->parameterBag instanceof FrozenParameterBag;
 110      }
 111  
 112      /**
 113       * Gets the service container parameter bag.
 114       *
 115       * @return ParameterBagInterface A ParameterBagInterface instance
 116       */
 117      public function getParameterBag()
 118      {
 119          return $this->parameterBag;
 120      }
 121  
 122      /**
 123       * Gets a parameter.
 124       *
 125       * @param string $name The parameter name
 126       *
 127       * @return mixed The parameter value
 128       *
 129       * @throws InvalidArgumentException if the parameter is not defined
 130       */
 131      public function getParameter($name)
 132      {
 133          return $this->parameterBag->get($name);
 134      }
 135  
 136      /**
 137       * Checks if a parameter exists.
 138       *
 139       * @param string $name The parameter name
 140       *
 141       * @return bool The presence of parameter in container
 142       */
 143      public function hasParameter($name)
 144      {
 145          return $this->parameterBag->has($name);
 146      }
 147  
 148      /**
 149       * Sets a parameter.
 150       *
 151       * @param string $name  The parameter name
 152       * @param mixed  $value The parameter value
 153       */
 154      public function setParameter($name, $value)
 155      {
 156          $this->parameterBag->set($name, $value);
 157      }
 158  
 159      /**
 160       * Sets a service.
 161       *
 162       * Setting a synthetic service to null resets it: has() returns false and get()
 163       * behaves in the same way as if the service was never created.
 164       *
 165       * @param string      $id      The service identifier
 166       * @param object|null $service The service instance
 167       */
 168      public function set($id, $service)
 169      {
 170          // Runs the internal initializer; used by the dumped container to include always-needed files
 171          if (isset($this->privates['service_container']) && $this->privates['service_container'] instanceof \Closure) {
 172              $initialize = $this->privates['service_container'];
 173              unset($this->privates['service_container']);
 174              $initialize();
 175          }
 176  
 177          $id = $this->normalizeId($id);
 178  
 179          if ('service_container' === $id) {
 180              throw new InvalidArgumentException('You cannot set service "service_container".');
 181          }
 182  
 183          if (isset($this->privates[$id]) || !(isset($this->fileMap[$id]) || isset($this->methodMap[$id]))) {
 184              if (!isset($this->privates[$id]) && !isset($this->getRemovedIds()[$id])) {
 185                  // no-op
 186              } elseif (null === $service) {
 187                  @trigger_error(sprintf('The "%s" service is private, unsetting it is deprecated since Symfony 3.2 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
 188                  unset($this->privates[$id]);
 189              } else {
 190                  @trigger_error(sprintf('The "%s" service is private, replacing it is deprecated since Symfony 3.2 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
 191              }
 192          } elseif (isset($this->services[$id])) {
 193              if (null === $service) {
 194                  @trigger_error(sprintf('The "%s" service is already initialized, unsetting it is deprecated since Symfony 3.3 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
 195              } else {
 196                  @trigger_error(sprintf('The "%s" service is already initialized, replacing it is deprecated since Symfony 3.3 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
 197              }
 198          }
 199  
 200          if (isset($this->aliases[$id])) {
 201              unset($this->aliases[$id]);
 202          }
 203  
 204          if (null === $service) {
 205              unset($this->services[$id]);
 206  
 207              return;
 208          }
 209  
 210          $this->services[$id] = $service;
 211      }
 212  
 213      /**
 214       * Returns true if the given service is defined.
 215       *
 216       * @param string $id The service identifier
 217       *
 218       * @return bool true if the service is defined, false otherwise
 219       */
 220      public function has($id)
 221      {
 222          for ($i = 2;;) {
 223              if (isset($this->privates[$id])) {
 224                  @trigger_error(sprintf('The "%s" service is private, checking for its existence is deprecated since Symfony 3.2 and will fail in 4.0.', $id), \E_USER_DEPRECATED);
 225              }
 226              if (isset($this->aliases[$id])) {
 227                  $id = $this->aliases[$id];
 228              }
 229              if (isset($this->services[$id])) {
 230                  return true;
 231              }
 232              if ('service_container' === $id) {
 233                  return true;
 234              }
 235  
 236              if (isset($this->fileMap[$id]) || isset($this->methodMap[$id])) {
 237                  return true;
 238              }
 239  
 240              if (--$i && $id !== $normalizedId = $this->normalizeId($id)) {
 241                  $id = $normalizedId;
 242                  continue;
 243              }
 244  
 245              // We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder,
 246              // and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper)
 247              if (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class && method_exists($this, 'get'.strtr($id, $this->underscoreMap).'Service')) {
 248                  @trigger_error('Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', \E_USER_DEPRECATED);
 249  
 250                  return true;
 251              }
 252  
 253              return false;
 254          }
 255      }
 256  
 257      /**
 258       * Gets a service.
 259       *
 260       * If a service is defined both through a set() method and
 261       * with a get{$id}Service() method, the former has always precedence.
 262       *
 263       * @param string $id              The service identifier
 264       * @param int    $invalidBehavior The behavior when the service does not exist
 265       *
 266       * @return object|null The associated service
 267       *
 268       * @throws ServiceCircularReferenceException When a circular reference is detected
 269       * @throws ServiceNotFoundException          When the service is not defined
 270       * @throws \Exception                        if an exception has been thrown when the service has been resolved
 271       *
 272       * @see Reference
 273       */
 274      public function get($id, $invalidBehavior = /* self::EXCEPTION_ON_INVALID_REFERENCE */ 1)
 275      {
 276          // Attempt to retrieve the service by checking first aliases then
 277          // available services. Service IDs are case insensitive, however since
 278          // this method can be called thousands of times during a request, avoid
 279          // calling $this->normalizeId($id) unless necessary.
 280          for ($i = 2;;) {
 281              if (isset($this->privates[$id])) {
 282                  @trigger_error(sprintf('The "%s" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead.', $id), \E_USER_DEPRECATED);
 283              }
 284              if (isset($this->aliases[$id])) {
 285                  $id = $this->aliases[$id];
 286              }
 287  
 288              // Re-use shared service instance if it exists.
 289              if (isset($this->services[$id])) {
 290                  return $this->services[$id];
 291              }
 292              if ('service_container' === $id) {
 293                  return $this;
 294              }
 295  
 296              if (isset($this->loading[$id])) {
 297                  throw new ServiceCircularReferenceException($id, array_merge(array_keys($this->loading), [$id]));
 298              }
 299  
 300              $this->loading[$id] = true;
 301  
 302              try {
 303                  if (isset($this->fileMap[$id])) {
 304                      return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $this->load($this->fileMap[$id]);
 305                  } elseif (isset($this->methodMap[$id])) {
 306                      return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $this->{$this->methodMap[$id]}();
 307                  } elseif (--$i && $id !== $normalizedId = $this->normalizeId($id)) {
 308                      unset($this->loading[$id]);
 309                      $id = $normalizedId;
 310                      continue;
 311                  } elseif (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class && method_exists($this, $method = 'get'.strtr($id, $this->underscoreMap).'Service')) {
 312                      // We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder,
 313                      // and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper)
 314                      @trigger_error('Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', \E_USER_DEPRECATED);
 315  
 316                      return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $this->{$method}();
 317                  }
 318  
 319                  break;
 320              } catch (\Exception $e) {
 321                  unset($this->services[$id]);
 322  
 323                  throw $e;
 324              } finally {
 325                  unset($this->loading[$id]);
 326              }
 327          }
 328  
 329          if (/* self::EXCEPTION_ON_INVALID_REFERENCE */ 1 === $invalidBehavior) {
 330              if (!$id) {
 331                  throw new ServiceNotFoundException($id);
 332              }
 333              if (isset($this->syntheticIds[$id])) {
 334                  throw new ServiceNotFoundException($id, null, null, [], sprintf('The "%s" service is synthetic, it needs to be set at boot time before it can be used.', $id));
 335              }
 336              if (isset($this->getRemovedIds()[$id])) {
 337                  throw new ServiceNotFoundException($id, null, null, [], sprintf('The "%s" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.', $id));
 338              }
 339  
 340              $alternatives = [];
 341              foreach ($this->getServiceIds() as $knownId) {
 342                  $lev = levenshtein($id, $knownId);
 343                  if ($lev <= \strlen($id) / 3 || false !== strpos($knownId, $id)) {
 344                      $alternatives[] = $knownId;
 345                  }
 346              }
 347  
 348              throw new ServiceNotFoundException($id, null, null, $alternatives);
 349          }
 350      }
 351  
 352      /**
 353       * Returns true if the given service has actually been initialized.
 354       *
 355       * @param string $id The service identifier
 356       *
 357       * @return bool true if service has already been initialized, false otherwise
 358       */
 359      public function initialized($id)
 360      {
 361          $id = $this->normalizeId($id);
 362  
 363          if (isset($this->privates[$id])) {
 364              @trigger_error(sprintf('Checking for the initialization of the "%s" private service is deprecated since Symfony 3.4 and won\'t be supported anymore in Symfony 4.0.', $id), \E_USER_DEPRECATED);
 365          }
 366  
 367          if (isset($this->aliases[$id])) {
 368              $id = $this->aliases[$id];
 369          }
 370  
 371          if ('service_container' === $id) {
 372              return false;
 373          }
 374  
 375          return isset($this->services[$id]);
 376      }
 377  
 378      /**
 379       * {@inheritdoc}
 380       */
 381      public function reset()
 382      {
 383          $this->services = [];
 384      }
 385  
 386      /**
 387       * Gets all service ids.
 388       *
 389       * @return string[] An array of all defined service ids
 390       */
 391      public function getServiceIds()
 392      {
 393          $ids = [];
 394  
 395          if (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class) {
 396              // We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder,
 397              // and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper)
 398              @trigger_error('Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', \E_USER_DEPRECATED);
 399  
 400              foreach (get_class_methods($this) as $method) {
 401                  if (preg_match('/^get(.+)Service$/', $method, $match)) {
 402                      $ids[] = self::underscore($match[1]);
 403                  }
 404              }
 405          }
 406          $ids[] = 'service_container';
 407  
 408          return array_map('strval', array_unique(array_merge($ids, array_keys($this->methodMap), array_keys($this->fileMap), array_keys($this->aliases), array_keys($this->services))));
 409      }
 410  
 411      /**
 412       * Gets service ids that existed at compile time.
 413       *
 414       * @return array
 415       */
 416      public function getRemovedIds()
 417      {
 418          return [];
 419      }
 420  
 421      /**
 422       * Camelizes a string.
 423       *
 424       * @param string $id A string to camelize
 425       *
 426       * @return string The camelized string
 427       */
 428      public static function camelize($id)
 429      {
 430          return strtr(ucwords(strtr($id, ['_' => ' ', '.' => '_ ', '\\' => '_ '])), [' ' => '']);
 431      }
 432  
 433      /**
 434       * A string to underscore.
 435       *
 436       * @param string $id The string to underscore
 437       *
 438       * @return string The underscored string
 439       */
 440      public static function underscore($id)
 441      {
 442          return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], ['\\1_\\2', '\\1_\\2'], str_replace('_', '.', $id)));
 443      }
 444  
 445      /**
 446       * Creates a service by requiring its factory file.
 447       */
 448      protected function load($file)
 449      {
 450          return require $file;
 451      }
 452  
 453      /**
 454       * Fetches a variable from the environment.
 455       *
 456       * @param string $name The name of the environment variable
 457       *
 458       * @return mixed The value to use for the provided environment variable name
 459       *
 460       * @throws EnvNotFoundException When the environment variable is not found and has no default value
 461       */
 462      protected function getEnv($name)
 463      {
 464          if (isset($this->resolving[$envName = "env($name)"])) {
 465              throw new ParameterCircularReferenceException(array_keys($this->resolving));
 466          }
 467          if (isset($this->envCache[$name]) || \array_key_exists($name, $this->envCache)) {
 468              return $this->envCache[$name];
 469          }
 470          if (!$this->has($id = 'container.env_var_processors_locator')) {
 471              $this->set($id, new ServiceLocator([]));
 472          }
 473          if (!$this->getEnv) {
 474              $this->getEnv = new \ReflectionMethod($this, __FUNCTION__);
 475              $this->getEnv->setAccessible(true);
 476              $this->getEnv = $this->getEnv->getClosure($this);
 477          }
 478          $processors = $this->get($id);
 479  
 480          if (false !== $i = strpos($name, ':')) {
 481              $prefix = substr($name, 0, $i);
 482              $localName = substr($name, 1 + $i);
 483          } else {
 484              $prefix = 'string';
 485              $localName = $name;
 486          }
 487          $processor = $processors->has($prefix) ? $processors->get($prefix) : new EnvVarProcessor($this);
 488  
 489          $this->resolving[$envName] = true;
 490          try {
 491              return $this->envCache[$name] = $processor->getEnv($prefix, $localName, $this->getEnv);
 492          } finally {
 493              unset($this->resolving[$envName]);
 494          }
 495      }
 496  
 497      /**
 498       * Returns the case sensitive id used at registration time.
 499       *
 500       * @param string $id
 501       *
 502       * @return string
 503       *
 504       * @internal
 505       */
 506      public function normalizeId($id)
 507      {
 508          if (!\is_string($id)) {
 509              $id = (string) $id;
 510          }
 511          if (isset($this->normalizedIds[$normalizedId = strtolower($id)])) {
 512              $normalizedId = $this->normalizedIds[$normalizedId];
 513              if ($id !== $normalizedId) {
 514                  @trigger_error(sprintf('Service identifiers will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.3.', $id, $normalizedId), \E_USER_DEPRECATED);
 515              }
 516          } else {
 517              $normalizedId = $this->normalizedIds[$normalizedId] = $id;
 518          }
 519  
 520          return $normalizedId;
 521      }
 522  
 523      private function __clone()
 524      {
 525      }
 526  }


Generated: Mon Oct 4 17:42:11 2021 Cross-referenced by PHPXref 0.7.1