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.
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: 09.10.2024, 12:56 - Dateigröße: 9.44 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\DependencyInjection\ContainerBuilder;
 015  use Symfony\Component\DependencyInjection\Definition;
 016  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
 017  use Symfony\Component\DependencyInjection\Reference;
 018   
 019  /**
 020   * Guesses constructor arguments of services definitions and try to instantiate services if necessary.
 021   *
 022   * @author Kévin Dunglas <dunglas@gmail.com>
 023   */
 024  class AutowirePass implements CompilerPassInterface
 025  {
 026      private $container;
 027      private $reflectionClasses = array();
 028      private $definedTypes = array();
 029      private $types;
 030      private $notGuessableTypes = array();
 031   
 032      /**
 033       * {@inheritdoc}
 034       */
 035      public function process(ContainerBuilder $container)
 036      {
 037          $throwingAutoloader = function ($class) { throw new \ReflectionException(sprintf('Class %s does not exist', $class)); };
 038          spl_autoload_register($throwingAutoloader);
 039   
 040          try {
 041              $this->container = $container;
 042              foreach ($container->getDefinitions() as $id => $definition) {
 043                  if ($definition->isAutowired()) {
 044                      $this->completeDefinition($id, $definition);
 045                  }
 046              }
 047          } catch (\Exception $e) {
 048          } catch (\Throwable $e) {
 049          }
 050   
 051          spl_autoload_unregister($throwingAutoloader);
 052   
 053          // Free memory and remove circular reference to container
 054          $this->container = null;
 055          $this->reflectionClasses = array();
 056          $this->definedTypes = array();
 057          $this->types = null;
 058          $this->notGuessableTypes = array();
 059   
 060          if (isset($e)) {
 061              throw $e;
 062          }
 063      }
 064   
 065      /**
 066       * Wires the given definition.
 067       *
 068       * @param string     $id
 069       * @param Definition $definition
 070       *
 071       * @throws RuntimeException
 072       */
 073      private function completeDefinition($id, Definition $definition)
 074      {
 075          if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
 076              return;
 077          }
 078   
 079          $this->container->addClassResource($reflectionClass);
 080   
 081          if (!$constructor = $reflectionClass->getConstructor()) {
 082              return;
 083          }
 084   
 085          $arguments = $definition->getArguments();
 086          foreach ($constructor->getParameters() as $index => $parameter) {
 087              if (array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
 088                  continue;
 089              }
 090   
 091              try {
 092                  if (!$typeHint = $parameter->getClass()) {
 093                      // no default value? Then fail
 094                      if (!$parameter->isOptional()) {
 095                          throw new RuntimeException(sprintf('Unable to autowire argument index %d ($%s) for the service "%s". If this is an object, give it a type-hint. Otherwise, specify this argument\'s value explicitly.', $index, $parameter->name, $id));
 096                      }
 097   
 098                      // specifically pass the default value
 099                      $arguments[$index] = $parameter->getDefaultValue();
 100   
 101                      continue;
 102                  }
 103   
 104                  if (null === $this->types) {
 105                      $this->populateAvailableTypes();
 106                  }
 107   
 108                  if (isset($this->types[$typeHint->name]) && !isset($this->notGuessableTypes[$typeHint->name])) {
 109                      $value = new Reference($this->types[$typeHint->name]);
 110                  } else {
 111                      try {
 112                          $value = $this->createAutowiredDefinition($typeHint, $id);
 113                      } catch (RuntimeException $e) {
 114                          if ($parameter->allowsNull()) {
 115                              $value = null;
 116                          } elseif ($parameter->isDefaultValueAvailable()) {
 117                              $value = $parameter->getDefaultValue();
 118                          } else {
 119                              throw $e;
 120                          }
 121                      }
 122                  }
 123              } catch (\ReflectionException $e) {
 124                  // Typehint against a non-existing class
 125   
 126                  if (!$parameter->isDefaultValueAvailable()) {
 127                      throw new RuntimeException(sprintf('Cannot autowire argument %s for %s because the type-hinted class does not exist (%s).', $index + 1, $definition->getClass(), $e->getMessage()), 0, $e);
 128                  }
 129   
 130                  $value = $parameter->getDefaultValue();
 131              }
 132   
 133              $arguments[$index] = $value;
 134          }
 135   
 136          // it's possible index 1 was set, then index 0, then 2, etc
 137          // make sure that we re-order so they're injected as expected
 138          ksort($arguments);
 139          $definition->setArguments($arguments);
 140      }
 141   
 142      /**
 143       * Populates the list of available types.
 144       */
 145      private function populateAvailableTypes()
 146      {
 147          $this->types = array();
 148   
 149          foreach ($this->container->getDefinitions() as $id => $definition) {
 150              $this->populateAvailableType($id, $definition);
 151          }
 152      }
 153   
 154      /**
 155       * Populates the list of available types for a given definition.
 156       *
 157       * @param string     $id
 158       * @param Definition $definition
 159       */
 160      private function populateAvailableType($id, Definition $definition)
 161      {
 162          // Never use abstract services
 163          if ($definition->isAbstract()) {
 164              return;
 165          }
 166   
 167          foreach ($definition->getAutowiringTypes() as $type) {
 168              $this->definedTypes[$type] = true;
 169              $this->types[$type] = $id;
 170          }
 171   
 172          if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
 173              return;
 174          }
 175   
 176          foreach ($reflectionClass->getInterfaces() as $reflectionInterface) {
 177              $this->set($reflectionInterface->name, $id);
 178          }
 179   
 180          do {
 181              $this->set($reflectionClass->name, $id);
 182          } while ($reflectionClass = $reflectionClass->getParentClass());
 183      }
 184   
 185      /**
 186       * Associates a type and a service id if applicable.
 187       *
 188       * @param string $type
 189       * @param string $id
 190       */
 191      private function set($type, $id)
 192      {
 193          if (isset($this->definedTypes[$type])) {
 194              return;
 195          }
 196   
 197          if (!isset($this->types[$type])) {
 198              $this->types[$type] = $id;
 199   
 200              return;
 201          }
 202   
 203          if ($this->types[$type] === $id) {
 204              return;
 205          }
 206   
 207          if (!isset($this->notGuessableTypes[$type])) {
 208              $this->notGuessableTypes[$type] = true;
 209              $this->types[$type] = (array) $this->types[$type];
 210          }
 211   
 212          $this->types[$type][] = $id;
 213      }
 214   
 215      /**
 216       * Registers a definition for the type if possible or throws an exception.
 217       *
 218       * @param \ReflectionClass $typeHint
 219       * @param string           $id
 220       *
 221       * @return Reference A reference to the registered definition
 222       *
 223       * @throws RuntimeException
 224       */
 225      private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
 226      {
 227          if (isset($this->notGuessableTypes[$typeHint->name])) {
 228              $classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
 229              $matchingServices = implode(', ', $this->types[$typeHint->name]);
 230   
 231              throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices));
 232          }
 233   
 234          if (!$typeHint->isInstantiable()) {
 235              $classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
 236              throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface));
 237          }
 238   
 239          $argumentId = sprintf('autowired.%s', $typeHint->name);
 240   
 241          $argumentDefinition = $this->container->register($argumentId, $typeHint->name);
 242          $argumentDefinition->setPublic(false);
 243   
 244          $this->populateAvailableType($argumentId, $argumentDefinition);
 245   
 246          try {
 247              $this->completeDefinition($argumentId, $argumentDefinition);
 248          } catch (RuntimeException $e) {
 249              $classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
 250              $message = sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface);
 251              throw new RuntimeException($message, 0, $e);
 252          }
 253   
 254          return new Reference($argumentId);
 255      }
 256   
 257      /**
 258       * Retrieves the reflection class associated with the given service.
 259       *
 260       * @param string     $id
 261       * @param Definition $definition
 262       *
 263       * @return \ReflectionClass|false
 264       */
 265      private function getReflectionClass($id, Definition $definition)
 266      {
 267          if (isset($this->reflectionClasses[$id])) {
 268              return $this->reflectionClasses[$id];
 269          }
 270   
 271          // Cannot use reflection if the class isn't set
 272          if (!$class = $definition->getClass()) {
 273              return false;
 274          }
 275   
 276          $class = $this->container->getParameterBag()->resolveValue($class);
 277   
 278          try {
 279              $reflector = new \ReflectionClass($class);
 280          } catch (\ReflectionException $e) {
 281              $reflector = false;
 282          }
 283   
 284          return $this->reflectionClasses[$id] = $reflector;
 285      }
 286  }
 287