Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

AutowirePass.php

Zuletzt modifiziert: 01.05.2026, 11:27 - Dateigröße: 21.56 KiB


 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\Compiler;
 013   
 014  use Symfony\Component\Config\Resource\ClassExistenceResource;
 015  use Symfony\Component\DependencyInjection\Config\AutowireServiceResource;
 016  use Symfony\Component\DependencyInjection\ContainerBuilder;
 017  use Symfony\Component\DependencyInjection\Definition;
 018  use Symfony\Component\DependencyInjection\Exception\AutowiringFailedException;
 019  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
 020  use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
 021  use Symfony\Component\DependencyInjection\TypedReference;
 022   
 023  /**
 024   * Inspects existing service definitions and wires the autowired ones using the type hints of their classes.
 025   *
 026   * @author Kévin Dunglas <dunglas@gmail.com>
 027   * @author Nicolas Grekas <p@tchwork.com>
 028   */
 029  class AutowirePass extends AbstractRecursivePass
 030  {
 031      private $definedTypes = [];
 032      private $types;
 033      private $ambiguousServiceTypes;
 034      private $autowired = [];
 035      private $lastFailure;
 036      private $throwOnAutowiringException;
 037      private $autowiringExceptions = [];
 038      private $strictMode;
 039   
 040      /**
 041       * @param bool $throwOnAutowireException Errors can be retrieved via Definition::getErrors()
 042       */
 043      public function __construct($throwOnAutowireException = true)
 044      {
 045          $this->throwOnAutowiringException = $throwOnAutowireException;
 046      }
 047   
 048      /**
 049       * @deprecated since version 3.4, to be removed in 4.0.
 050       *
 051       * @return AutowiringFailedException[]
 052       */
 053      public function getAutowiringExceptions()
 054      {
 055          @trigger_error('Calling AutowirePass::getAutowiringExceptions() is deprecated since Symfony 3.4 and will be removed in 4.0. Use Definition::getErrors() instead.', \E_USER_DEPRECATED);
 056   
 057          return $this->autowiringExceptions;
 058      }
 059   
 060      /**
 061       * {@inheritdoc}
 062       */
 063      public function process(ContainerBuilder $container)
 064      {
 065          // clear out any possibly stored exceptions from before
 066          $this->autowiringExceptions = [];
 067          $this->strictMode = $container->hasParameter('container.autowiring.strict_mode') && $container->getParameter('container.autowiring.strict_mode');
 068   
 069          try {
 070              parent::process($container);
 071          } finally {
 072              $this->definedTypes = [];
 073              $this->types = null;
 074              $this->ambiguousServiceTypes = null;
 075              $this->autowired = [];
 076          }
 077      }
 078   
 079      /**
 080       * Creates a resource to help know if this service has changed.
 081       *
 082       * @return AutowireServiceResource
 083       *
 084       * @deprecated since version 3.3, to be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.
 085       */
 086      public static function createResourceForClass(\ReflectionClass $reflectionClass)
 087      {
 088          @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.', \E_USER_DEPRECATED);
 089   
 090          $metadata = [];
 091   
 092          foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
 093              if (!$reflectionMethod->isStatic()) {
 094                  $metadata[$reflectionMethod->name] = self::getResourceMetadataForMethod($reflectionMethod);
 095              }
 096          }
 097   
 098          return new AutowireServiceResource($reflectionClass->name, $reflectionClass->getFileName(), $metadata);
 099      }
 100   
 101      /**
 102       * {@inheritdoc}
 103       */
 104      protected function processValue($value, $isRoot = false)
 105      {
 106          try {
 107              return $this->doProcessValue($value, $isRoot);
 108          } catch (AutowiringFailedException $e) {
 109              if ($this->throwOnAutowiringException) {
 110                  throw $e;
 111              }
 112   
 113              $this->autowiringExceptions[] = $e;
 114              $this->container->getDefinition($this->currentId)->addError($e->getMessage());
 115   
 116              return parent::processValue($value, $isRoot);
 117          }
 118      }
 119   
 120      private function doProcessValue($value, $isRoot = false)
 121      {
 122          if ($value instanceof TypedReference) {
 123              if ($ref = $this->getAutowiredReference($value, $value->getRequiringClass() ? sprintf('for "%s" in "%s"', $value->getType(), $value->getRequiringClass()) : '')) {
 124                  return $ref;
 125              }
 126              $this->container->log($this, $this->createTypeNotFoundMessage($value, 'it'));
 127          }
 128          $value = parent::processValue($value, $isRoot);
 129   
 130          if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
 131              return $value;
 132          }
 133          if (!$reflectionClass = $this->container->getReflectionClass($value->getClass(), false)) {
 134              $this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" cannot be loaded.', $this->currentId, $value->getClass()));
 135   
 136              return $value;
 137          }
 138   
 139          $methodCalls = $value->getMethodCalls();
 140   
 141          try {
 142              $constructor = $this->getConstructor($value, false);
 143          } catch (RuntimeException $e) {
 144              throw new AutowiringFailedException($this->currentId, $e->getMessage(), 0, $e);
 145          }
 146   
 147          if ($constructor) {
 148              array_unshift($methodCalls, [$constructor, $value->getArguments()]);
 149          }
 150   
 151          $methodCalls = $this->autowireCalls($reflectionClass, $methodCalls);
 152   
 153          if ($constructor) {
 154              list(, $arguments) = array_shift($methodCalls);
 155   
 156              if ($arguments !== $value->getArguments()) {
 157                  $value->setArguments($arguments);
 158              }
 159          }
 160   
 161          if ($methodCalls !== $value->getMethodCalls()) {
 162              $value->setMethodCalls($methodCalls);
 163          }
 164   
 165          return $value;
 166      }
 167   
 168      /**
 169       * @return array
 170       */
 171      private function autowireCalls(\ReflectionClass $reflectionClass, array $methodCalls)
 172      {
 173          foreach ($methodCalls as $i => $call) {
 174              list($method, $arguments) = $call;
 175   
 176              if ($method instanceof \ReflectionFunctionAbstract) {
 177                  $reflectionMethod = $method;
 178              } else {
 179                  $definition = new Definition($reflectionClass->name);
 180                  try {
 181                      $reflectionMethod = $this->getReflectionMethod($definition, $method);
 182                  } catch (RuntimeException $e) {
 183                      if ($definition->getFactory()) {
 184                          continue;
 185                      }
 186                      throw $e;
 187                  }
 188              }
 189   
 190              $arguments = $this->autowireMethod($reflectionMethod, $arguments);
 191   
 192              if ($arguments !== $call[1]) {
 193                  $methodCalls[$i][1] = $arguments;
 194              }
 195          }
 196   
 197          return $methodCalls;
 198      }
 199   
 200      /**
 201       * Autowires the constructor or a method.
 202       *
 203       * @return array The autowired arguments
 204       *
 205       * @throws AutowiringFailedException
 206       */
 207      private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments)
 208      {
 209          $class = $reflectionMethod instanceof \ReflectionMethod ? $reflectionMethod->class : $this->currentId;
 210          $method = $reflectionMethod->name;
 211          $parameters = $reflectionMethod->getParameters();
 212          if (method_exists('ReflectionMethod', 'isVariadic') && $reflectionMethod->isVariadic()) {
 213              array_pop($parameters);
 214          }
 215   
 216          foreach ($parameters as $index => $parameter) {
 217              if (\array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
 218                  continue;
 219              }
 220   
 221              $type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, true);
 222   
 223              if (!$type) {
 224                  if (isset($arguments[$index])) {
 225                      continue;
 226                  }
 227   
 228                  // no default value? Then fail
 229                  if (!$parameter->isDefaultValueAvailable()) {
 230                      // For core classes, isDefaultValueAvailable() can
 231                      // be false when isOptional() returns true. If the
 232                      // argument *is* optional, allow it to be missing
 233                      if ($parameter->isOptional()) {
 234                          continue;
 235                      }
 236                      $type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, false);
 237                      $type = $type ? sprintf('is type-hinted "%s"', $type) : 'has no type-hint';
 238   
 239                      throw new AutowiringFailedException($this->currentId, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s()" %s, you should configure its value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method, $type));
 240                  }
 241   
 242                  // specifically pass the default value
 243                  $arguments[$index] = $parameter->getDefaultValue();
 244   
 245                  continue;
 246              }
 247   
 248              if (!$value = $this->getAutowiredReference($ref = new TypedReference($type, $type, !$parameter->isOptional() ? $class : ''), 'for '.sprintf('argument "$%s" of method "%s()"', $parameter->name, $class.'::'.$method))) {
 249                  $failureMessage = $this->createTypeNotFoundMessage($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
 250   
 251                  if ($parameter->isDefaultValueAvailable()) {
 252                      $value = $parameter->getDefaultValue();
 253                  } elseif (!$parameter->allowsNull()) {
 254                      throw new AutowiringFailedException($this->currentId, $failureMessage);
 255                  }
 256                  $this->container->log($this, $failureMessage);
 257              }
 258   
 259              $arguments[$index] = $value;
 260          }
 261   
 262          if ($parameters && !isset($arguments[++$index])) {
 263              while (0 <= --$index) {
 264                  $parameter = $parameters[$index];
 265                  if (!$parameter->isDefaultValueAvailable() || $parameter->getDefaultValue() !== $arguments[$index]) {
 266                      break;
 267                  }
 268                  unset($arguments[$index]);
 269              }
 270          }
 271   
 272          // it's possible index 1 was set, then index 0, then 2, etc
 273          // make sure that we re-order so they're injected as expected
 274          ksort($arguments);
 275   
 276          return $arguments;
 277      }
 278   
 279      /**
 280       * @return TypedReference|null A reference to the service matching the given type, if any
 281       */
 282      private function getAutowiredReference(TypedReference $reference, $deprecationMessage)
 283      {
 284          $this->lastFailure = null;
 285          $type = $reference->getType();
 286   
 287          if ($type !== $this->container->normalizeId($reference) || ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract())) {
 288              return $reference;
 289          }
 290   
 291          if (null === $this->types) {
 292              $this->populateAvailableTypes($this->strictMode);
 293          }
 294   
 295          if (isset($this->definedTypes[$type])) {
 296              return new TypedReference($this->types[$type], $type);
 297          }
 298   
 299          if (!$this->strictMode && isset($this->types[$type])) {
 300              $message = 'Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won\'t be supported in version 4.0.';
 301              if ($aliasSuggestion = $this->getAliasesSuggestionForType($type = $reference->getType(), $deprecationMessage)) {
 302                  $message .= ' '.$aliasSuggestion;
 303              } else {
 304                  $message .= sprintf(' You should %s the "%s" service to "%s" instead.', isset($this->types[$this->types[$type]]) ? 'alias' : 'rename (or alias)', $this->types[$type], $type);
 305              }
 306   
 307              @trigger_error($message, \E_USER_DEPRECATED);
 308   
 309              return new TypedReference($this->types[$type], $type);
 310          }
 311   
 312          if (!$reference->canBeAutoregistered() || isset($this->types[$type]) || isset($this->ambiguousServiceTypes[$type])) {
 313              return null;
 314          }
 315   
 316          if (isset($this->autowired[$type])) {
 317              return $this->autowired[$type] ? new TypedReference($this->autowired[$type], $type) : null;
 318          }
 319   
 320          if (!$this->strictMode) {
 321              return $this->createAutowiredDefinition($type);
 322          }
 323   
 324          return null;
 325      }
 326   
 327      /**
 328       * Populates the list of available types.
 329       */
 330      private function populateAvailableTypes($onlyAutowiringTypes = false)
 331      {
 332          $this->types = [];
 333          if (!$onlyAutowiringTypes) {
 334              $this->ambiguousServiceTypes = [];
 335          }
 336   
 337          foreach ($this->container->getDefinitions() as $id => $definition) {
 338              $this->populateAvailableType($id, $definition, $onlyAutowiringTypes);
 339          }
 340      }
 341   
 342      /**
 343       * Populates the list of available types for a given definition.
 344       *
 345       * @param string $id
 346       */
 347      private function populateAvailableType($id, Definition $definition, $onlyAutowiringTypes)
 348      {
 349          // Never use abstract services
 350          if ($definition->isAbstract()) {
 351              return;
 352          }
 353   
 354          foreach ($definition->getAutowiringTypes(false) as $type) {
 355              $this->definedTypes[$type] = true;
 356              $this->types[$type] = $id;
 357              unset($this->ambiguousServiceTypes[$type]);
 358          }
 359   
 360          if ($onlyAutowiringTypes) {
 361              return;
 362          }
 363   
 364          if (preg_match('/^\d+_[^~]++~[._a-zA-Z\d]{7}$/', $id) || $definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), false)) {
 365              return;
 366          }
 367   
 368          foreach ($reflectionClass->getInterfaces() as $reflectionInterface) {
 369              $this->set($reflectionInterface->name, $id);
 370          }
 371   
 372          do {
 373              $this->set($reflectionClass->name, $id);
 374          } while ($reflectionClass = $reflectionClass->getParentClass());
 375      }
 376   
 377      /**
 378       * Associates a type and a service id if applicable.
 379       *
 380       * @param string $type
 381       * @param string $id
 382       */
 383      private function set($type, $id)
 384      {
 385          if (isset($this->definedTypes[$type])) {
 386              return;
 387          }
 388   
 389          // is this already a type/class that is known to match multiple services?
 390          if (isset($this->ambiguousServiceTypes[$type])) {
 391              $this->ambiguousServiceTypes[$type][] = $id;
 392   
 393              return;
 394          }
 395   
 396          // check to make sure the type doesn't match multiple services
 397          if (!isset($this->types[$type]) || $this->types[$type] === $id) {
 398              $this->types[$type] = $id;
 399   
 400              return;
 401          }
 402   
 403          // keep an array of all services matching this type
 404          if (!isset($this->ambiguousServiceTypes[$type])) {
 405              $this->ambiguousServiceTypes[$type] = [$this->types[$type]];
 406              unset($this->types[$type]);
 407          }
 408          $this->ambiguousServiceTypes[$type][] = $id;
 409      }
 410   
 411      /**
 412       * Registers a definition for the type if possible or throws an exception.
 413       *
 414       * @param string $type
 415       *
 416       * @return TypedReference|null A reference to the registered definition
 417       */
 418      private function createAutowiredDefinition($type)
 419      {
 420          if (!($typeHint = $this->container->getReflectionClass($type, false)) || !$typeHint->isInstantiable()) {
 421              return null;
 422          }
 423   
 424          $currentId = $this->currentId;
 425          $this->currentId = $type;
 426          $this->autowired[$type] = $argumentId = sprintf('autowired.%s', $type);
 427          $argumentDefinition = new Definition($type);
 428          $argumentDefinition->setPublic(false);
 429          $argumentDefinition->setAutowired(true);
 430   
 431          try {
 432              $originalThrowSetting = $this->throwOnAutowiringException;
 433              $this->throwOnAutowiringException = true;
 434              $this->processValue($argumentDefinition, true);
 435              $this->container->setDefinition($argumentId, $argumentDefinition);
 436          } catch (AutowiringFailedException $e) {
 437              $this->autowired[$type] = false;
 438              $this->lastFailure = $e->getMessage();
 439              $this->container->log($this, $this->lastFailure);
 440   
 441              return null;
 442          } finally {
 443              $this->throwOnAutowiringException = $originalThrowSetting;
 444              $this->currentId = $currentId;
 445          }
 446   
 447          @trigger_error(sprintf('Relying on service auto-registration for type "%s" is deprecated since Symfony 3.4 and won\'t be supported in 4.0. Create a service named "%s" instead.', $type, $type), \E_USER_DEPRECATED);
 448   
 449          $this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId));
 450   
 451          return new TypedReference($argumentId, $type);
 452      }
 453   
 454      private function createTypeNotFoundMessage(TypedReference $reference, $label)
 455      {
 456          $trackResources = $this->container->isTrackingResources();
 457          $this->container->setResourceTracking(false);
 458          try {
 459              if ($r = $this->container->getReflectionClass($type = $reference->getType(), false)) {
 460                  $alternatives = $this->createTypeAlternatives($reference);
 461              }
 462          } finally {
 463              $this->container->setResourceTracking($trackResources);
 464          }
 465   
 466          if (!$r) {
 467              // either $type does not exist or a parent class does not exist
 468              try {
 469                  $resource = new ClassExistenceResource($type, false);
 470                  // isFresh() will explode ONLY if a parent class/trait does not exist
 471                  $resource->isFresh(0);
 472                  $parentMsg = false;
 473              } catch (\ReflectionException $e) {
 474                  $parentMsg = $e->getMessage();
 475              }
 476   
 477              $message = sprintf('has type "%s" but this class %s.', $type, $parentMsg ? sprintf('is missing a parent class (%s)', $parentMsg) : 'was not found');
 478          } else {
 479              $message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists';
 480              $message = sprintf('references %s "%s" but %s.%s', $r->isInterface() ? 'interface' : 'class', $type, $message, $alternatives);
 481   
 482              if ($r->isInterface() && !$alternatives) {
 483                  $message .= ' Did you create a class that implements this interface?';
 484              }
 485          }
 486   
 487          $message = sprintf('Cannot autowire service "%s": %s %s', $this->currentId, $label, $message);
 488   
 489          if (null !== $this->lastFailure) {
 490              $message = $this->lastFailure."\n".$message;
 491              $this->lastFailure = null;
 492          }
 493   
 494          return $message;
 495      }
 496   
 497      private function createTypeAlternatives(TypedReference $reference)
 498      {
 499          // try suggesting available aliases first
 500          if ($message = $this->getAliasesSuggestionForType($type = $reference->getType())) {
 501              return ' '.$message;
 502          }
 503          if (null === $this->ambiguousServiceTypes) {
 504              $this->populateAvailableTypes();
 505          }
 506   
 507          if (isset($this->ambiguousServiceTypes[$type])) {
 508              $message = sprintf('one of these existing services: "%s"', implode('", "', $this->ambiguousServiceTypes[$type]));
 509          } elseif (isset($this->types[$type])) {
 510              $message = sprintf('the existing "%s" service', $this->types[$type]);
 511          } elseif ($reference->getRequiringClass() && !$reference->canBeAutoregistered() && !$this->strictMode) {
 512              return ' It cannot be auto-registered because it is from a different root namespace.';
 513          } else {
 514              return '';
 515          }
 516   
 517          return sprintf(' You should maybe alias this %s to %s.', class_exists($type, false) ? 'class' : 'interface', $message);
 518      }
 519   
 520      /**
 521       * @deprecated since version 3.3, to be removed in 4.0.
 522       */
 523      private static function getResourceMetadataForMethod(\ReflectionMethod $method)
 524      {
 525          $methodArgumentsMetadata = [];
 526          foreach ($method->getParameters() as $parameter) {
 527              try {
 528                  if (method_exists($parameter, 'getType')) {
 529                      $type = $parameter->getType();
 530                      if ($type && !$type->isBuiltin()) {
 531                          $class = new \ReflectionClass($type instanceof \ReflectionNamedType ? $type->getName() : (string) $type);
 532                      } else {
 533                          $class = null;
 534                      }
 535                  } else {
 536                      $class = $parameter->getClass();
 537                  }
 538              } catch (\ReflectionException $e) {
 539                  // type-hint is against a non-existent class
 540                  $class = false;
 541              }
 542   
 543              $isVariadic = method_exists($parameter, 'isVariadic') && $parameter->isVariadic();
 544              $methodArgumentsMetadata[] = [
 545                  'class' => $class,
 546                  'isOptional' => $parameter->isOptional(),
 547                  'defaultValue' => ($parameter->isOptional() && !$isVariadic) ? $parameter->getDefaultValue() : null,
 548              ];
 549          }
 550   
 551          return $methodArgumentsMetadata;
 552      }
 553   
 554      private function getAliasesSuggestionForType($type, $extraContext = null)
 555      {
 556          $aliases = [];
 557          foreach (class_parents($type) + class_implements($type) as $parent) {
 558              if ($this->container->has($parent) && !$this->container->findDefinition($parent)->isAbstract()) {
 559                  $aliases[] = $parent;
 560              }
 561          }
 562   
 563          $extraContext = $extraContext ? ' '.$extraContext : '';
 564          if (1 < $len = \count($aliases)) {
 565              $message = sprintf('Try changing the type-hint%s to one of its parents: ', $extraContext);
 566              for ($i = 0, --$len; $i < $len; ++$i) {
 567                  $message .= sprintf('%s "%s", ', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
 568              }
 569              $message .= sprintf('or %s "%s".', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]);
 570   
 571              return $message;
 572          }
 573   
 574          if ($aliases) {
 575              return sprintf('Try changing the type-hint%s to "%s" instead.', $extraContext, $aliases[0]);
 576          }
 577   
 578          return null;
 579      }
 580  }
 581