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