[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
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 Psr\Container\ContainerInterface as PsrContainerInterface; 15 use Symfony\Component\Config\Resource\ClassExistenceResource; 16 use Symfony\Component\Config\Resource\ComposerResource; 17 use Symfony\Component\Config\Resource\DirectoryResource; 18 use Symfony\Component\Config\Resource\FileExistenceResource; 19 use Symfony\Component\Config\Resource\FileResource; 20 use Symfony\Component\Config\Resource\GlobResource; 21 use Symfony\Component\Config\Resource\ReflectionClassResource; 22 use Symfony\Component\Config\Resource\ResourceInterface; 23 use Symfony\Component\DependencyInjection\Argument\IteratorArgument; 24 use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; 25 use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; 26 use Symfony\Component\DependencyInjection\Compiler\Compiler; 27 use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 28 use Symfony\Component\DependencyInjection\Compiler\PassConfig; 29 use Symfony\Component\DependencyInjection\Compiler\ResolveEnvPlaceholdersPass; 30 use Symfony\Component\DependencyInjection\Exception\BadMethodCallException; 31 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; 32 use Symfony\Component\DependencyInjection\Exception\LogicException; 33 use Symfony\Component\DependencyInjection\Exception\RuntimeException; 34 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; 35 use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; 36 use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; 37 use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface; 38 use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator; 39 use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; 40 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; 41 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; 42 use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; 43 use Symfony\Component\ExpressionLanguage\Expression; 44 use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; 45 46 /** 47 * ContainerBuilder is a DI container that provides an API to easily describe services. 48 * 49 * @author Fabien Potencier <fabien@symfony.com> 50 */ 51 class ContainerBuilder extends Container implements TaggedContainerInterface 52 { 53 /** 54 * @var ExtensionInterface[] 55 */ 56 private $extensions = []; 57 58 /** 59 * @var ExtensionInterface[] 60 */ 61 private $extensionsByNs = []; 62 63 /** 64 * @var Definition[] 65 */ 66 private $definitions = []; 67 68 /** 69 * @var Alias[] 70 */ 71 private $aliasDefinitions = []; 72 73 /** 74 * @var ResourceInterface[] 75 */ 76 private $resources = []; 77 78 private $extensionConfigs = []; 79 80 /** 81 * @var Compiler 82 */ 83 private $compiler; 84 85 private $trackResources; 86 87 /** 88 * @var InstantiatorInterface|null 89 */ 90 private $proxyInstantiator; 91 92 /** 93 * @var ExpressionLanguage|null 94 */ 95 private $expressionLanguage; 96 97 /** 98 * @var ExpressionFunctionProviderInterface[] 99 */ 100 private $expressionLanguageProviders = []; 101 102 /** 103 * @var string[] with tag names used by findTaggedServiceIds 104 */ 105 private $usedTags = []; 106 107 /** 108 * @var string[][] a map of env var names to their placeholders 109 */ 110 private $envPlaceholders = []; 111 112 /** 113 * @var int[] a map of env vars to their resolution counter 114 */ 115 private $envCounters = []; 116 117 /** 118 * @var string[] the list of vendor directories 119 */ 120 private $vendors; 121 122 private $autoconfiguredInstanceof = []; 123 124 private $removedIds = []; 125 126 private $removedBindingIds = []; 127 128 private static $internalTypes = [ 129 'int' => true, 130 'float' => true, 131 'string' => true, 132 'bool' => true, 133 'resource' => true, 134 'object' => true, 135 'array' => true, 136 'null' => true, 137 'callable' => true, 138 'iterable' => true, 139 'mixed' => true, 140 ]; 141 142 public function __construct(ParameterBagInterface $parameterBag = null) 143 { 144 parent::__construct($parameterBag); 145 146 $this->trackResources = interface_exists('Symfony\Component\Config\Resource\ResourceInterface'); 147 $this->setDefinition('service_container', (new Definition(ContainerInterface::class))->setSynthetic(true)->setPublic(true)); 148 $this->setAlias(PsrContainerInterface::class, new Alias('service_container', false)); 149 $this->setAlias(ContainerInterface::class, new Alias('service_container', false)); 150 } 151 152 /** 153 * @var \ReflectionClass[] a list of class reflectors 154 */ 155 private $classReflectors; 156 157 /** 158 * Sets the track resources flag. 159 * 160 * If you are not using the loaders and therefore don't want 161 * to depend on the Config component, set this flag to false. 162 * 163 * @param bool $track True if you want to track resources, false otherwise 164 */ 165 public function setResourceTracking($track) 166 { 167 $this->trackResources = (bool) $track; 168 } 169 170 /** 171 * Checks if resources are tracked. 172 * 173 * @return bool true If resources are tracked, false otherwise 174 */ 175 public function isTrackingResources() 176 { 177 return $this->trackResources; 178 } 179 180 /** 181 * Sets the instantiator to be used when fetching proxies. 182 */ 183 public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator) 184 { 185 $this->proxyInstantiator = $proxyInstantiator; 186 } 187 188 public function registerExtension(ExtensionInterface $extension) 189 { 190 $this->extensions[$extension->getAlias()] = $extension; 191 192 if (false !== $extension->getNamespace()) { 193 $this->extensionsByNs[$extension->getNamespace()] = $extension; 194 } 195 } 196 197 /** 198 * Returns an extension by alias or namespace. 199 * 200 * @param string $name An alias or a namespace 201 * 202 * @return ExtensionInterface An extension instance 203 * 204 * @throws LogicException if the extension is not registered 205 */ 206 public function getExtension($name) 207 { 208 if (isset($this->extensions[$name])) { 209 return $this->extensions[$name]; 210 } 211 212 if (isset($this->extensionsByNs[$name])) { 213 return $this->extensionsByNs[$name]; 214 } 215 216 throw new LogicException(sprintf('Container extension "%s" is not registered.', $name)); 217 } 218 219 /** 220 * Returns all registered extensions. 221 * 222 * @return ExtensionInterface[] An array of ExtensionInterface 223 */ 224 public function getExtensions() 225 { 226 return $this->extensions; 227 } 228 229 /** 230 * Checks if we have an extension. 231 * 232 * @param string $name The name of the extension 233 * 234 * @return bool If the extension exists 235 */ 236 public function hasExtension($name) 237 { 238 return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]); 239 } 240 241 /** 242 * Returns an array of resources loaded to build this configuration. 243 * 244 * @return ResourceInterface[] An array of resources 245 */ 246 public function getResources() 247 { 248 return array_values($this->resources); 249 } 250 251 /** 252 * @return $this 253 */ 254 public function addResource(ResourceInterface $resource) 255 { 256 if (!$this->trackResources) { 257 return $this; 258 } 259 260 if ($resource instanceof GlobResource && $this->inVendors($resource->getPrefix())) { 261 return $this; 262 } 263 264 $this->resources[(string) $resource] = $resource; 265 266 return $this; 267 } 268 269 /** 270 * Sets the resources for this configuration. 271 * 272 * @param ResourceInterface[] $resources An array of resources 273 * 274 * @return $this 275 */ 276 public function setResources(array $resources) 277 { 278 if (!$this->trackResources) { 279 return $this; 280 } 281 282 $this->resources = $resources; 283 284 return $this; 285 } 286 287 /** 288 * Adds the object class hierarchy as resources. 289 * 290 * @param object|string $object An object instance or class name 291 * 292 * @return $this 293 */ 294 public function addObjectResource($object) 295 { 296 if ($this->trackResources) { 297 if (\is_object($object)) { 298 $object = \get_class($object); 299 } 300 if (!isset($this->classReflectors[$object])) { 301 $this->classReflectors[$object] = new \ReflectionClass($object); 302 } 303 $class = $this->classReflectors[$object]; 304 305 foreach ($class->getInterfaceNames() as $name) { 306 if (null === $interface = &$this->classReflectors[$name]) { 307 $interface = new \ReflectionClass($name); 308 } 309 $file = $interface->getFileName(); 310 if (false !== $file && file_exists($file)) { 311 $this->fileExists($file); 312 } 313 } 314 do { 315 $file = $class->getFileName(); 316 if (false !== $file && file_exists($file)) { 317 $this->fileExists($file); 318 } 319 foreach ($class->getTraitNames() as $name) { 320 $this->addObjectResource($name); 321 } 322 } while ($class = $class->getParentClass()); 323 } 324 325 return $this; 326 } 327 328 /** 329 * Adds the given class hierarchy as resources. 330 * 331 * @return $this 332 * 333 * @deprecated since version 3.3, to be removed in 4.0. Use addObjectResource() or getReflectionClass() instead. 334 */ 335 public function addClassResource(\ReflectionClass $class) 336 { 337 @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); 338 339 return $this->addObjectResource($class->name); 340 } 341 342 /** 343 * Retrieves the requested reflection class and registers it for resource tracking. 344 * 345 * @param string $class 346 * @param bool $throw 347 * 348 * @return \ReflectionClass|null 349 * 350 * @throws \ReflectionException when a parent class/interface/trait is not found and $throw is true 351 * 352 * @final 353 */ 354 public function getReflectionClass($class, $throw = true) 355 { 356 if (!$class = $this->getParameterBag()->resolveValue($class)) { 357 return null; 358 } 359 360 if (isset(self::$internalTypes[$class])) { 361 return null; 362 } 363 364 $resource = $classReflector = null; 365 366 try { 367 if (isset($this->classReflectors[$class])) { 368 $classReflector = $this->classReflectors[$class]; 369 } elseif (class_exists(ClassExistenceResource::class)) { 370 $resource = new ClassExistenceResource($class, false); 371 $classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class); 372 } else { 373 $classReflector = class_exists($class) ? new \ReflectionClass($class) : false; 374 } 375 } catch (\ReflectionException $e) { 376 if ($throw) { 377 throw $e; 378 } 379 } 380 381 if ($this->trackResources) { 382 if (!$classReflector) { 383 $this->addResource($resource ?: new ClassExistenceResource($class, false)); 384 } elseif (!$classReflector->isInternal()) { 385 $path = $classReflector->getFileName(); 386 387 if (!$this->inVendors($path)) { 388 $this->addResource(new ReflectionClassResource($classReflector, $this->vendors)); 389 } 390 } 391 $this->classReflectors[$class] = $classReflector; 392 } 393 394 return $classReflector ?: null; 395 } 396 397 /** 398 * Checks whether the requested file or directory exists and registers the result for resource tracking. 399 * 400 * @param string $path The file or directory path for which to check the existence 401 * @param bool|string $trackContents Whether to track contents of the given resource. If a string is passed, 402 * it will be used as pattern for tracking contents of the requested directory 403 * 404 * @return bool 405 * 406 * @final 407 */ 408 public function fileExists($path, $trackContents = true) 409 { 410 $exists = file_exists($path); 411 412 if (!$this->trackResources || $this->inVendors($path)) { 413 return $exists; 414 } 415 416 if (!$exists) { 417 $this->addResource(new FileExistenceResource($path)); 418 419 return $exists; 420 } 421 422 if (is_dir($path)) { 423 if ($trackContents) { 424 $this->addResource(new DirectoryResource($path, \is_string($trackContents) ? $trackContents : null)); 425 } else { 426 $this->addResource(new GlobResource($path, '/*', false)); 427 } 428 } elseif ($trackContents) { 429 $this->addResource(new FileResource($path)); 430 } 431 432 return $exists; 433 } 434 435 /** 436 * Loads the configuration for an extension. 437 * 438 * @param string $extension The extension alias or namespace 439 * @param array $values An array of values that customizes the extension 440 * 441 * @return $this 442 * 443 * @throws BadMethodCallException When this ContainerBuilder is compiled 444 * @throws \LogicException if the extension is not registered 445 */ 446 public function loadFromExtension($extension, array $values = null) 447 { 448 if ($this->isCompiled()) { 449 throw new BadMethodCallException('Cannot load from an extension on a compiled container.'); 450 } 451 452 if (\func_num_args() < 2) { 453 $values = []; 454 } 455 456 $namespace = $this->getExtension($extension)->getAlias(); 457 458 $this->extensionConfigs[$namespace][] = $values; 459 460 return $this; 461 } 462 463 /** 464 * Adds a compiler pass. 465 * 466 * @param CompilerPassInterface $pass A compiler pass 467 * @param string $type The type of compiler pass 468 * @param int $priority Used to sort the passes 469 * 470 * @return $this 471 */ 472 public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/) 473 { 474 if (\func_num_args() >= 3) { 475 $priority = func_get_arg(2); 476 } else { 477 if (__CLASS__ !== static::class) { 478 $r = new \ReflectionMethod($this, __FUNCTION__); 479 if (__CLASS__ !== $r->getDeclaringClass()->getName()) { 480 @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); 481 } 482 } 483 484 $priority = 0; 485 } 486 487 $this->getCompiler()->addPass($pass, $type, $priority); 488 489 $this->addObjectResource($pass); 490 491 return $this; 492 } 493 494 /** 495 * Returns the compiler pass config which can then be modified. 496 * 497 * @return PassConfig The compiler pass config 498 */ 499 public function getCompilerPassConfig() 500 { 501 return $this->getCompiler()->getPassConfig(); 502 } 503 504 /** 505 * Returns the compiler. 506 * 507 * @return Compiler The compiler 508 */ 509 public function getCompiler() 510 { 511 if (null === $this->compiler) { 512 $this->compiler = new Compiler(); 513 } 514 515 return $this->compiler; 516 } 517 518 /** 519 * Sets a service. 520 * 521 * @param string $id The service identifier 522 * @param object|null $service The service instance 523 * 524 * @throws BadMethodCallException When this ContainerBuilder is compiled 525 */ 526 public function set($id, $service) 527 { 528 $id = $this->normalizeId($id); 529 530 if ($this->isCompiled() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) { 531 // setting a synthetic service on a compiled container is alright 532 throw new BadMethodCallException(sprintf('Setting service "%s" for an unknown or non-synthetic service definition on a compiled container is not allowed.', $id)); 533 } 534 535 unset($this->definitions[$id], $this->aliasDefinitions[$id], $this->removedIds[$id]); 536 537 parent::set($id, $service); 538 } 539 540 /** 541 * Removes a service definition. 542 * 543 * @param string $id The service identifier 544 */ 545 public function removeDefinition($id) 546 { 547 if (isset($this->definitions[$id = $this->normalizeId($id)])) { 548 unset($this->definitions[$id]); 549 $this->removedIds[$id] = true; 550 } 551 } 552 553 /** 554 * Returns true if the given service is defined. 555 * 556 * @param string $id The service identifier 557 * 558 * @return bool true if the service is defined, false otherwise 559 */ 560 public function has($id) 561 { 562 $id = $this->normalizeId($id); 563 564 return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || parent::has($id); 565 } 566 567 /** 568 * Gets a service. 569 * 570 * @param string $id The service identifier 571 * @param int $invalidBehavior The behavior when the service does not exist 572 * 573 * @return object|null The associated service 574 * 575 * @throws InvalidArgumentException when no definitions are available 576 * @throws ServiceCircularReferenceException When a circular reference is detected 577 * @throws ServiceNotFoundException When the service is not defined 578 * @throws \Exception 579 * 580 * @see Reference 581 */ 582 public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) 583 { 584 if ($this->isCompiled() && isset($this->removedIds[$id = $this->normalizeId($id)])) { 585 @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); 586 } 587 588 return $this->doGet($id, $invalidBehavior); 589 } 590 591 private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices = null, $isConstructorArgument = false) 592 { 593 $id = $this->normalizeId($id); 594 595 if (isset($inlineServices[$id])) { 596 return $inlineServices[$id]; 597 } 598 if (null === $inlineServices) { 599 $isConstructorArgument = true; 600 $inlineServices = []; 601 } 602 try { 603 if (ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $invalidBehavior) { 604 return parent::get($id, $invalidBehavior); 605 } 606 if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) { 607 return $service; 608 } 609 } catch (ServiceCircularReferenceException $e) { 610 if ($isConstructorArgument) { 611 throw $e; 612 } 613 } 614 615 if (!isset($this->definitions[$id]) && isset($this->aliasDefinitions[$id])) { 616 return $this->doGet((string) $this->aliasDefinitions[$id], $invalidBehavior, $inlineServices, $isConstructorArgument); 617 } 618 619 try { 620 $definition = $this->getDefinition($id); 621 } catch (ServiceNotFoundException $e) { 622 if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) { 623 return null; 624 } 625 626 throw $e; 627 } 628 629 if ($isConstructorArgument) { 630 $this->loading[$id] = true; 631 } 632 633 try { 634 return $this->createService($definition, $inlineServices, $isConstructorArgument, $id); 635 } finally { 636 if ($isConstructorArgument) { 637 unset($this->loading[$id]); 638 } 639 } 640 } 641 642 /** 643 * Merges a ContainerBuilder with the current ContainerBuilder configuration. 644 * 645 * Service definitions overrides the current defined ones. 646 * 647 * But for parameters, they are overridden by the current ones. It allows 648 * the parameters passed to the container constructor to have precedence 649 * over the loaded ones. 650 * 651 * $container = new ContainerBuilder(new ParameterBag(['foo' => 'bar'])); 652 * $loader = new LoaderXXX($container); 653 * $loader->load('resource_name'); 654 * $container->register('foo', 'stdClass'); 655 * 656 * In the above example, even if the loaded resource defines a foo 657 * parameter, the value will still be 'bar' as defined in the ContainerBuilder 658 * constructor. 659 * 660 * @throws BadMethodCallException When this ContainerBuilder is compiled 661 */ 662 public function merge(self $container) 663 { 664 if ($this->isCompiled()) { 665 throw new BadMethodCallException('Cannot merge on a compiled container.'); 666 } 667 668 $this->addDefinitions($container->getDefinitions()); 669 $this->addAliases($container->getAliases()); 670 $this->getParameterBag()->add($container->getParameterBag()->all()); 671 672 if ($this->trackResources) { 673 foreach ($container->getResources() as $resource) { 674 $this->addResource($resource); 675 } 676 } 677 678 foreach ($this->extensions as $name => $extension) { 679 if (!isset($this->extensionConfigs[$name])) { 680 $this->extensionConfigs[$name] = []; 681 } 682 683 $this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name)); 684 } 685 686 if ($this->getParameterBag() instanceof EnvPlaceholderParameterBag && $container->getParameterBag() instanceof EnvPlaceholderParameterBag) { 687 $envPlaceholders = $container->getParameterBag()->getEnvPlaceholders(); 688 $this->getParameterBag()->mergeEnvPlaceholders($container->getParameterBag()); 689 } else { 690 $envPlaceholders = []; 691 } 692 693 foreach ($container->envCounters as $env => $count) { 694 if (!$count && !isset($envPlaceholders[$env])) { 695 continue; 696 } 697 if (!isset($this->envCounters[$env])) { 698 $this->envCounters[$env] = $count; 699 } else { 700 $this->envCounters[$env] += $count; 701 } 702 } 703 704 foreach ($container->getAutoconfiguredInstanceof() as $interface => $childDefinition) { 705 if (isset($this->autoconfiguredInstanceof[$interface])) { 706 throw new InvalidArgumentException(sprintf('"%s" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.', $interface)); 707 } 708 709 $this->autoconfiguredInstanceof[$interface] = $childDefinition; 710 } 711 } 712 713 /** 714 * Returns the configuration array for the given extension. 715 * 716 * @param string $name The name of the extension 717 * 718 * @return array An array of configuration 719 */ 720 public function getExtensionConfig($name) 721 { 722 if (!isset($this->extensionConfigs[$name])) { 723 $this->extensionConfigs[$name] = []; 724 } 725 726 return $this->extensionConfigs[$name]; 727 } 728 729 /** 730 * Prepends a config array to the configs of the given extension. 731 * 732 * @param string $name The name of the extension 733 * @param array $config The config to set 734 */ 735 public function prependExtensionConfig($name, array $config) 736 { 737 if (!isset($this->extensionConfigs[$name])) { 738 $this->extensionConfigs[$name] = []; 739 } 740 741 array_unshift($this->extensionConfigs[$name], $config); 742 } 743 744 /** 745 * Compiles the container. 746 * 747 * This method passes the container to compiler 748 * passes whose job is to manipulate and optimize 749 * the container. 750 * 751 * The main compiler passes roughly do four things: 752 * 753 * * The extension configurations are merged; 754 * * Parameter values are resolved; 755 * * The parameter bag is frozen; 756 * * Extension loading is disabled. 757 * 758 * @param bool $resolveEnvPlaceholders Whether %env()% parameters should be resolved using the current 759 * env vars or be replaced by uniquely identifiable placeholders. 760 * Set to "true" when you want to use the current ContainerBuilder 761 * directly, keep to "false" when the container is dumped instead. 762 */ 763 public function compile(/*$resolveEnvPlaceholders = false*/) 764 { 765 if (1 <= \func_num_args()) { 766 $resolveEnvPlaceholders = func_get_arg(0); 767 } else { 768 if (__CLASS__ !== static::class) { 769 $r = new \ReflectionMethod($this, __FUNCTION__); 770 if (__CLASS__ !== $r->getDeclaringClass()->getName() && (1 > $r->getNumberOfParameters() || 'resolveEnvPlaceholders' !== $r->getParameters()[0]->name)) { 771 @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); 772 } 773 } 774 $resolveEnvPlaceholders = false; 775 } 776 $compiler = $this->getCompiler(); 777 778 if ($this->trackResources) { 779 foreach ($compiler->getPassConfig()->getPasses() as $pass) { 780 $this->addObjectResource($pass); 781 } 782 } 783 $bag = $this->getParameterBag(); 784 785 if ($resolveEnvPlaceholders && $bag instanceof EnvPlaceholderParameterBag) { 786 $compiler->addPass(new ResolveEnvPlaceholdersPass(), PassConfig::TYPE_AFTER_REMOVING, -1000); 787 } 788 789 $compiler->compile($this); 790 791 foreach ($this->definitions as $id => $definition) { 792 if ($this->trackResources && $definition->isLazy()) { 793 $this->getReflectionClass($definition->getClass()); 794 } 795 } 796 797 $this->extensionConfigs = []; 798 799 if ($bag instanceof EnvPlaceholderParameterBag) { 800 if ($resolveEnvPlaceholders) { 801 $this->parameterBag = new ParameterBag($this->resolveEnvPlaceholders($bag->all(), true)); 802 } 803 804 $this->envPlaceholders = $bag->getEnvPlaceholders(); 805 } 806 807 parent::compile(); 808 809 foreach ($this->definitions + $this->aliasDefinitions as $id => $definition) { 810 if (!$definition->isPublic() || $definition->isPrivate()) { 811 $this->removedIds[$id] = true; 812 } 813 } 814 } 815 816 /** 817 * {@inheritdoc} 818 */ 819 public function getServiceIds() 820 { 821 return array_map('strval', array_unique(array_merge(array_keys($this->getDefinitions()), array_keys($this->aliasDefinitions), parent::getServiceIds()))); 822 } 823 824 /** 825 * Gets removed service or alias ids. 826 * 827 * @return array 828 */ 829 public function getRemovedIds() 830 { 831 return $this->removedIds; 832 } 833 834 /** 835 * Adds the service aliases. 836 */ 837 public function addAliases(array $aliases) 838 { 839 foreach ($aliases as $alias => $id) { 840 $this->setAlias($alias, $id); 841 } 842 } 843 844 /** 845 * Sets the service aliases. 846 */ 847 public function setAliases(array $aliases) 848 { 849 $this->aliasDefinitions = []; 850 $this->addAliases($aliases); 851 } 852 853 /** 854 * Sets an alias for an existing service. 855 * 856 * @param string $alias The alias to create 857 * @param string|Alias $id The service to alias 858 * 859 * @return Alias 860 * 861 * @throws InvalidArgumentException if the id is not a string or an Alias 862 * @throws InvalidArgumentException if the alias is for itself 863 */ 864 public function setAlias($alias, $id) 865 { 866 $alias = $this->normalizeId($alias); 867 868 if ('' === $alias || '\\' === substr($alias, -1) || \strlen($alias) !== strcspn($alias, "\0\r\n'")) { 869 throw new InvalidArgumentException(sprintf('Invalid alias id: "%s".', $alias)); 870 } 871 872 if (\is_string($id)) { 873 $id = new Alias($this->normalizeId($id)); 874 } elseif (!$id instanceof Alias) { 875 throw new InvalidArgumentException('$id must be a string, or an Alias object.'); 876 } 877 878 if ($alias === (string) $id) { 879 throw new InvalidArgumentException(sprintf('An alias can not reference itself, got a circular reference on "%s".', $alias)); 880 } 881 882 unset($this->definitions[$alias], $this->removedIds[$alias]); 883 884 return $this->aliasDefinitions[$alias] = $id; 885 } 886 887 /** 888 * Removes an alias. 889 * 890 * @param string $alias The alias to remove 891 */ 892 public function removeAlias($alias) 893 { 894 if (isset($this->aliasDefinitions[$alias = $this->normalizeId($alias)])) { 895 unset($this->aliasDefinitions[$alias]); 896 $this->removedIds[$alias] = true; 897 } 898 } 899 900 /** 901 * Returns true if an alias exists under the given identifier. 902 * 903 * @param string $id The service identifier 904 * 905 * @return bool true if the alias exists, false otherwise 906 */ 907 public function hasAlias($id) 908 { 909 return isset($this->aliasDefinitions[$this->normalizeId($id)]); 910 } 911 912 /** 913 * Gets all defined aliases. 914 * 915 * @return Alias[] An array of aliases 916 */ 917 public function getAliases() 918 { 919 return $this->aliasDefinitions; 920 } 921 922 /** 923 * Gets an alias. 924 * 925 * @param string $id The service identifier 926 * 927 * @return Alias An Alias instance 928 * 929 * @throws InvalidArgumentException if the alias does not exist 930 */ 931 public function getAlias($id) 932 { 933 $id = $this->normalizeId($id); 934 935 if (!isset($this->aliasDefinitions[$id])) { 936 throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id)); 937 } 938 939 return $this->aliasDefinitions[$id]; 940 } 941 942 /** 943 * Registers a service definition. 944 * 945 * This methods allows for simple registration of service definition 946 * with a fluid interface. 947 * 948 * @param string $id The service identifier 949 * @param string|null $class The service class 950 * 951 * @return Definition A Definition instance 952 */ 953 public function register($id, $class = null) 954 { 955 return $this->setDefinition($id, new Definition($class)); 956 } 957 958 /** 959 * Registers an autowired service definition. 960 * 961 * This method implements a shortcut for using setDefinition() with 962 * an autowired definition. 963 * 964 * @param string $id The service identifier 965 * @param string|null $class The service class 966 * 967 * @return Definition The created definition 968 */ 969 public function autowire($id, $class = null) 970 { 971 return $this->setDefinition($id, (new Definition($class))->setAutowired(true)); 972 } 973 974 /** 975 * Adds the service definitions. 976 * 977 * @param Definition[] $definitions An array of service definitions 978 */ 979 public function addDefinitions(array $definitions) 980 { 981 foreach ($definitions as $id => $definition) { 982 $this->setDefinition($id, $definition); 983 } 984 } 985 986 /** 987 * Sets the service definitions. 988 * 989 * @param Definition[] $definitions An array of service definitions 990 */ 991 public function setDefinitions(array $definitions) 992 { 993 $this->definitions = []; 994 $this->addDefinitions($definitions); 995 } 996 997 /** 998 * Gets all service definitions. 999 * 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |