Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
Container.php
001 <?php
002
003 /*
004 * This file is part of the Symfony package.
005 *
006 * (c) Fabien Potencier <fabien@symfony.com>
007 *
008 * For the full copyright and license information, please view the LICENSE
009 * file that was distributed with this source code.
010 */
011
012 namespace Symfony\Component\DependencyInjection;
013
014 use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
015 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
016 use Symfony\Component\DependencyInjection\Exception\LogicException;
017 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
018 use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
019 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
020 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
021 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
022 use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
023
024 /**
025 * Container is a dependency injection container.
026 *
027 * It gives access to object instances (services).
028 *
029 * Services and parameters are simple key/pair stores.
030 *
031 * Parameter and service keys are case insensitive.
032 *
033 * A service id can contain lowercased letters, digits, underscores, and dots.
034 * Underscores are used to separate words, and dots to group services
035 * under namespaces:
036 *
037 * <ul>
038 * <li>request</li>
039 * <li>mysql_session_storage</li>
040 * <li>symfony.mysql_session_storage</li>
041 * </ul>
042 *
043 * A service can also be defined by creating a method named
044 * getXXXService(), where XXX is the camelized version of the id:
045 *
046 * <ul>
047 * <li>request -> getRequestService()</li>
048 * <li>mysql_session_storage -> getMysqlSessionStorageService()</li>
049 * <li>symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()</li>
050 * </ul>
051 *
052 * The container can have three possible behaviors when a service does not exist:
053 *
054 * * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception (the default)
055 * * NULL_ON_INVALID_REFERENCE: Returns null
056 * * IGNORE_ON_INVALID_REFERENCE: Ignores the wrapping command asking for the reference
057 * (for instance, ignore a setter if the service does not exist)
058 *
059 * @author Fabien Potencier <fabien@symfony.com>
060 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
061 */
062 class Container implements IntrospectableContainerInterface, ResettableContainerInterface
063 {
064 /**
065 * @var ParameterBagInterface
066 */
067 protected $parameterBag;
068
069 protected $services = array();
070 protected $methodMap = array();
071 protected $aliases = array();
072 protected $scopes = array();
073 protected $scopeChildren = array();
074 protected $scopedServices = array();
075 protected $scopeStacks = array();
076 protected $loading = array();
077
078 private $underscoreMap = array('_' => '', '.' => '_', '\\' => '_');
079
080 /**
081 * @param ParameterBagInterface $parameterBag A ParameterBagInterface instance
082 */
083 public function __construct(ParameterBagInterface $parameterBag = null)
084 {
085 $this->parameterBag = $parameterBag ?: new ParameterBag();
086 }
087
088 /**
089 * Compiles the container.
090 *
091 * This method does two things:
092 *
093 * * Parameter values are resolved;
094 * * The parameter bag is frozen.
095 */
096 public function compile()
097 {
098 $this->parameterBag->resolve();
099
100 $this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
101 }
102
103 /**
104 * Returns true if the container parameter bag are frozen.
105 *
106 * @return bool true if the container parameter bag are frozen, false otherwise
107 */
108 public function isFrozen()
109 {
110 return $this->parameterBag instanceof FrozenParameterBag;
111 }
112
113 /**
114 * Gets the service container parameter bag.
115 *
116 * @return ParameterBagInterface A ParameterBagInterface instance
117 */
118 public function getParameterBag()
119 {
120 return $this->parameterBag;
121 }
122
123 /**
124 * Gets a parameter.
125 *
126 * @param string $name The parameter name
127 *
128 * @return mixed The parameter value
129 *
130 * @throws InvalidArgumentException if the parameter is not defined
131 */
132 public function getParameter($name)
133 {
134 return $this->parameterBag->get($name);
135 }
136
137 /**
138 * Checks if a parameter exists.
139 *
140 * @param string $name The parameter name
141 *
142 * @return bool The presence of parameter in container
143 */
144 public function hasParameter($name)
145 {
146 return $this->parameterBag->has($name);
147 }
148
149 /**
150 * Sets a parameter.
151 *
152 * @param string $name The parameter name
153 * @param mixed $value The parameter value
154 */
155 public function setParameter($name, $value)
156 {
157 $this->parameterBag->set($name, $value);
158 }
159
160 /**
161 * Sets a service.
162 *
163 * Setting a service to null resets the service: has() returns false and get()
164 * behaves in the same way as if the service was never created.
165 *
166 * Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
167 *
168 * @param string $id The service identifier
169 * @param object $service The service instance
170 * @param string $scope The scope of the service
171 *
172 * @throws RuntimeException When trying to set a service in an inactive scope
173 * @throws InvalidArgumentException When trying to set a service in the prototype scope
174 */
175 public function set($id, $service, $scope = self::SCOPE_CONTAINER)
176 {
177 if (!in_array($scope, array('container', 'request')) || ('request' === $scope && 'request' !== $id)) {
178 @trigger_error('The concept of container scopes is deprecated since version 2.8 and will be removed in 3.0. Omit the third parameter.', E_USER_DEPRECATED);
179 }
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 (null === $service) {
212 if (self::SCOPE_CONTAINER !== $scope) {
213 unset($this->scopedServices[$scope][$id]);
214 }
215
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->getServiceIds() as $knownId) {
299 $lev = levenshtein($id, $knownId);
300 if ($lev <= strlen($id) / 3 || false !== strpos($knownId, $id)) {
301 $alternatives[] = $knownId;
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 * {@inheritdoc}
363 */
364 public function reset()
365 {
366 if (!empty($this->scopedServices)) {
367 throw new LogicException('Resetting the container is not allowed when a scope is active.');
368 }
369
370 $this->services = array();
371 }
372
373 /**
374 * Gets all service ids.
375 *
376 * @return array An array of all defined service ids
377 */
378 public function getServiceIds()
379 {
380 $ids = array();
381 foreach (get_class_methods($this) as $method) {
382 if (preg_match('/^get(.+)Service$/', $method, $match)) {
383 $ids[] = self::underscore($match[1]);
384 }
385 }
386 $ids[] = 'service_container';
387
388 return array_unique(array_merge($ids, array_keys($this->services)));
389 }
390
391 /**
392 * This is called when you enter a scope.
393 *
394 * @param string $name
395 *
396 * @throws RuntimeException When the parent scope is inactive
397 * @throws InvalidArgumentException When the scope does not exist
398 *
399 * @deprecated since version 2.8, to be removed in 3.0.
400 */
401 public function enterScope($name)
402 {
403 if ('request' !== $name) {
404 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
405 }
406
407 if (!isset($this->scopes[$name])) {
408 throw new InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name));
409 }
410
411 if (self::SCOPE_CONTAINER !== $this->scopes[$name] && !isset($this->scopedServices[$this->scopes[$name]])) {
412 throw new RuntimeException(sprintf('The parent scope "%s" must be active when entering this scope.', $this->scopes[$name]));
413 }
414
415 // check if a scope of this name is already active, if so we need to
416 // remove all services of this scope, and those of any of its child
417 // scopes from the global services map
418 if (isset($this->scopedServices[$name])) {
419 $services = array($this->services, $name => $this->scopedServices[$name]);
420 unset($this->scopedServices[$name]);
421
422 foreach ($this->scopeChildren[$name] as $child) {
423 if (isset($this->scopedServices[$child])) {
424 $services[$child] = $this->scopedServices[$child];
425 unset($this->scopedServices[$child]);
426 }
427 }
428
429 // update global map
430 $this->services = call_user_func_array('array_diff_key', $services);
431 array_shift($services);
432
433 // add stack entry for this scope so we can restore the removed services later
434 if (!isset($this->scopeStacks[$name])) {
435 $this->scopeStacks[$name] = new \SplStack();
436 }
437 $this->scopeStacks[$name]->push($services);
438 }
439
440 $this->scopedServices[$name] = array();
441 }
442
443 /**
444 * This is called to leave the current scope, and move back to the parent
445 * scope.
446 *
447 * @param string $name The name of the scope to leave
448 *
449 * @throws InvalidArgumentException if the scope is not active
450 *
451 * @deprecated since version 2.8, to be removed in 3.0.
452 */
453 public function leaveScope($name)
454 {
455 if ('request' !== $name) {
456 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
457 }
458
459 if (!isset($this->scopedServices[$name])) {
460 throw new InvalidArgumentException(sprintf('The scope "%s" is not active.', $name));
461 }
462
463 // remove all services of this scope, or any of its child scopes from
464 // the global service map
465 $services = array($this->services, $this->scopedServices[$name]);
466 unset($this->scopedServices[$name]);
467
468 foreach ($this->scopeChildren[$name] as $child) {
469 if (isset($this->scopedServices[$child])) {
470 $services[] = $this->scopedServices[$child];
471 unset($this->scopedServices[$child]);
472 }
473 }
474
475 // update global map
476 $this->services = call_user_func_array('array_diff_key', $services);
477
478 // check if we need to restore services of a previous scope of this type
479 if (isset($this->scopeStacks[$name]) && count($this->scopeStacks[$name]) > 0) {
480 $services = $this->scopeStacks[$name]->pop();
481 $this->scopedServices += $services;
482
483 if ($this->scopeStacks[$name]->isEmpty()) {
484 unset($this->scopeStacks[$name]);
485 }
486
487 foreach ($services as $array) {
488 foreach ($array as $id => $service) {
489 $this->set($id, $service, $name);
490 }
491 }
492 }
493 }
494
495 /**
496 * Adds a scope to the container.
497 *
498 * @param ScopeInterface $scope
499 *
500 * @throws InvalidArgumentException
501 *
502 * @deprecated since version 2.8, to be removed in 3.0.
503 */
504 public function addScope(ScopeInterface $scope)
505 {
506 $name = $scope->getName();
507 $parentScope = $scope->getParentName();
508
509 if ('request' !== $name) {
510 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
511 }
512 if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) {
513 throw new InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name));
514 }
515 if (isset($this->scopes[$name])) {
516 throw new InvalidArgumentException(sprintf('A scope with name "%s" already exists.', $name));
517 }
518 if (self::SCOPE_CONTAINER !== $parentScope && !isset($this->scopes[$parentScope])) {
519 throw new InvalidArgumentException(sprintf('The parent scope "%s" does not exist, or is invalid.', $parentScope));
520 }
521
522 $this->scopes[$name] = $parentScope;
523 $this->scopeChildren[$name] = array();
524
525 // normalize the child relations
526 while ($parentScope !== self::SCOPE_CONTAINER) {
527 $this->scopeChildren[$parentScope][] = $name;
528 $parentScope = $this->scopes[$parentScope];
529 }
530 }
531
532 /**
533 * Returns whether this container has a certain scope.
534 *
535 * @param string $name The name of the scope
536 *
537 * @return bool
538 *
539 * @deprecated since version 2.8, to be removed in 3.0.
540 */
541 public function hasScope($name)
542 {
543 if ('request' !== $name) {
544 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
545 }
546
547 return isset($this->scopes[$name]);
548 }
549
550 /**
551 * Returns whether this scope is currently active.
552 *
553 * This does not actually check if the passed scope actually exists.
554 *
555 * @param string $name
556 *
557 * @return bool
558 *
559 * @deprecated since version 2.8, to be removed in 3.0.
560 */
561 public function isScopeActive($name)
562 {
563 @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
564
565 return isset($this->scopedServices[$name]);
566 }
567
568 /**
569 * Camelizes a string.
570 *
571 * @param string $id A string to camelize
572 *
573 * @return string The camelized string
574 */
575 public static function camelize($id)
576 {
577 return strtr(ucwords(strtr($id, array('_' => ' ', '.' => '_ ', '\\' => '_ '))), array(' ' => ''));
578 }
579
580 /**
581 * A string to underscore.
582 *
583 * @param string $id The string to underscore
584 *
585 * @return string The underscored string
586 */
587 public static function underscore($id)
588 {
589 return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), str_replace('_', '.', $id)));
590 }
591
592 private function __clone()
593 {
594 }
595 }
596