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