[ Index ] |
PHP Cross Reference of phpBB-3.2.11-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 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |