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