Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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

PhpDumper.php

Zuletzt modifiziert: 09.10.2024, 12:58 - Dateigröße: 41.92 KiB


0001  <?php
0002   
0003  /*
0004   * This file is part of the Symfony package.
0005   *
0006   * (c) Fabien Potencier <fabien@symfony.com>
0007   *
0008   * For the full copyright and license information, please view the LICENSE
0009   * file that was distributed with this source code.
0010   */
0011   
0012  namespace Symfony\Component\DependencyInjection\Dumper;
0013   
0014  use Symfony\Component\DependencyInjection\Variable;
0015  use Symfony\Component\DependencyInjection\Definition;
0016  use Symfony\Component\DependencyInjection\ContainerBuilder;
0017  use Symfony\Component\DependencyInjection\Container;
0018  use Symfony\Component\DependencyInjection\ContainerInterface;
0019  use Symfony\Component\DependencyInjection\Reference;
0020  use Symfony\Component\DependencyInjection\Parameter;
0021  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
0022  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
0023  use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
0024  use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
0025  use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
0026   
0027  /**
0028   * PhpDumper dumps a service container as a PHP class.
0029   *
0030   * @author Fabien Potencier <fabien@symfony.com>
0031   * @author Johannes M. Schmitt <schmittjoh@gmail.com>
0032   *
0033   * @api
0034   */
0035  class PhpDumper extends Dumper
0036  {
0037      /**
0038       * Characters that might appear in the generated variable name as first character
0039       * @var string
0040       */
0041      const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz';
0042   
0043      /**
0044       * Characters that might appear in the generated variable name as any but the first character
0045       * @var string
0046       */
0047      const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_';
0048   
0049      private $inlinedDefinitions;
0050      private $definitionVariables;
0051      private $referenceVariables;
0052      private $variableCount;
0053      private $reservedVariables = array('instance', 'class');
0054   
0055      /**
0056       * @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
0057       */
0058      private $proxyDumper;
0059   
0060      /**
0061       * {@inheritdoc}
0062       *
0063       * @api
0064       */
0065      public function __construct(ContainerBuilder $container)
0066      {
0067          parent::__construct($container);
0068   
0069          $this->inlinedDefinitions = new \SplObjectStorage();
0070      }
0071   
0072      /**
0073       * Sets the dumper to be used when dumping proxies in the generated container.
0074       *
0075       * @param ProxyDumper $proxyDumper
0076       */
0077      public function setProxyDumper(ProxyDumper $proxyDumper)
0078      {
0079          $this->proxyDumper = $proxyDumper;
0080      }
0081   
0082      /**
0083       * Dumps the service container as a PHP class.
0084       *
0085       * Available options:
0086       *
0087       *  * class:      The class name
0088       *  * base_class: The base class name
0089       *
0090       * @param array $options An array of options
0091       *
0092       * @return string A PHP class representing of the service container
0093       *
0094       * @api
0095       */
0096      public function dump(array $options = array())
0097      {
0098          $options = array_merge(array(
0099              'class'      => 'ProjectServiceContainer',
0100              'base_class' => 'Container',
0101          ), $options);
0102   
0103          $code = $this->startClass($options['class'], $options['base_class']);
0104   
0105          if ($this->container->isFrozen()) {
0106              $code .= $this->addFrozenConstructor();
0107          } else {
0108              $code .= $this->addConstructor();
0109          }
0110   
0111          $code .=
0112              $this->addServices().
0113              $this->addDefaultParametersMethod().
0114              $this->endClass().
0115              $this->addProxyClasses()
0116          ;
0117   
0118          return $code;
0119      }
0120   
0121      /**
0122       * Retrieves the currently set proxy dumper or instantiates one.
0123       *
0124       * @return ProxyDumper
0125       */
0126      private function getProxyDumper()
0127      {
0128          if (!$this->proxyDumper) {
0129              $this->proxyDumper = new NullDumper();
0130          }
0131   
0132          return $this->proxyDumper;
0133      }
0134   
0135      /**
0136       * Generates Service local temp variables.
0137       *
0138       * @param string $cId
0139       * @param string $definition
0140       *
0141       * @return string
0142       */
0143      private function addServiceLocalTempVariables($cId, $definition)
0144      {
0145          static $template = "        \$%s = %s;\n";
0146   
0147          $localDefinitions = array_merge(
0148              array($definition),
0149              $this->getInlinedDefinitions($definition)
0150          );
0151   
0152          $calls = $behavior = array();
0153          foreach ($localDefinitions as $iDefinition) {
0154              $this->getServiceCallsFromArguments($iDefinition->getArguments(), $calls, $behavior);
0155              $this->getServiceCallsFromArguments($iDefinition->getMethodCalls(), $calls, $behavior);
0156              $this->getServiceCallsFromArguments($iDefinition->getProperties(), $calls, $behavior);
0157          }
0158   
0159          $code = '';
0160          foreach ($calls as $id => $callCount) {
0161              if ('service_container' === $id || $id === $cId) {
0162                  continue;
0163              }
0164   
0165              if ($callCount > 1) {
0166                  $name = $this->getNextVariableName();
0167                  $this->referenceVariables[$id] = new Variable($name);
0168   
0169                  if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id]) {
0170                      $code .= sprintf($template, $name, $this->getServiceCall($id));
0171                  } else {
0172                      $code .= sprintf($template, $name, $this->getServiceCall($id, new Reference($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)));
0173                  }
0174              }
0175          }
0176   
0177          if ('' !== $code) {
0178              $code .= "\n";
0179          }
0180   
0181          return $code;
0182      }
0183   
0184      /**
0185       * Generates code for the proxies to be attached after the container class
0186       *
0187       * @return string
0188       */
0189      private function addProxyClasses()
0190      {
0191          /* @var $definitions Definition[] */
0192          $definitions = array_filter(
0193              $this->container->getDefinitions(),
0194              array($this->getProxyDumper(), 'isProxyCandidate')
0195          );
0196          $code = '';
0197   
0198          foreach ($definitions as $definition) {
0199              $code .= "\n".$this->getProxyDumper()->getProxyCode($definition);
0200          }
0201   
0202          return $code;
0203      }
0204   
0205      /**
0206       * Generates the require_once statement for service includes.
0207       *
0208       * @param string     $id         The service id
0209       * @param Definition $definition
0210       *
0211       * @return string
0212       */
0213      private function addServiceInclude($id, $definition)
0214      {
0215          $template = "        require_once %s;\n";
0216          $code = '';
0217   
0218          if (null !== $file = $definition->getFile()) {
0219              $code .= sprintf($template, $this->dumpValue($file));
0220          }
0221   
0222          foreach ($this->getInlinedDefinitions($definition) as $definition) {
0223              if (null !== $file = $definition->getFile()) {
0224                  $code .= sprintf($template, $this->dumpValue($file));
0225              }
0226          }
0227   
0228          if ('' !== $code) {
0229              $code .= "\n";
0230          }
0231   
0232          return $code;
0233      }
0234   
0235      /**
0236       * Generates the inline definition of a service.
0237       *
0238       * @param string     $id
0239       * @param Definition $definition
0240       *
0241       * @return string
0242       *
0243       * @throws RuntimeException When the factory definition is incomplete
0244       * @throws ServiceCircularReferenceException When a circular reference is detected
0245       */
0246      private function addServiceInlinedDefinitions($id, $definition)
0247      {
0248          $code = '';
0249          $variableMap = $this->definitionVariables;
0250          $nbOccurrences = new \SplObjectStorage();
0251          $processed = new \SplObjectStorage();
0252          $inlinedDefinitions = $this->getInlinedDefinitions($definition);
0253   
0254          foreach ($inlinedDefinitions as $definition) {
0255              if (false === $nbOccurrences->contains($definition)) {
0256                  $nbOccurrences->offsetSet($definition, 1);
0257              } else {
0258                  $i = $nbOccurrences->offsetGet($definition);
0259                  $nbOccurrences->offsetSet($definition, $i + 1);
0260              }
0261          }
0262   
0263          foreach ($inlinedDefinitions as $sDefinition) {
0264              if ($processed->contains($sDefinition)) {
0265                  continue;
0266              }
0267              $processed->offsetSet($sDefinition);
0268   
0269              $class = $this->dumpValue($sDefinition->getClass());
0270              if ($nbOccurrences->offsetGet($sDefinition) > 1 || $sDefinition->getMethodCalls() || $sDefinition->getProperties() || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) {
0271                  $name = $this->getNextVariableName();
0272                  $variableMap->offsetSet($sDefinition, new Variable($name));
0273   
0274                  // a construct like:
0275                  // $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a);
0276                  // this is an indication for a wrong implementation, you can circumvent this problem
0277                  // by setting up your service structure like this:
0278                  // $b = new ServiceB();
0279                  // $a = new ServiceA(ServiceB $b);
0280                  // $b->setServiceA(ServiceA $a);
0281                  if ($this->hasReference($id, $sDefinition->getArguments())) {
0282                      throw new ServiceCircularReferenceException($id, array($id));
0283                  }
0284   
0285                  $code .= $this->addNewInstance($id, $sDefinition, '$'.$name, ' = ');
0286   
0287                  if (!$this->hasReference($id, $sDefinition->getMethodCalls(), true) && !$this->hasReference($id, $sDefinition->getProperties(), true)) {
0288                      $code .= $this->addServiceMethodCalls(null, $sDefinition, $name);
0289                      $code .= $this->addServiceProperties(null, $sDefinition, $name);
0290                      $code .= $this->addServiceConfigurator(null, $sDefinition, $name);
0291                  }
0292   
0293                  $code .= "\n";
0294              }
0295          }
0296   
0297          return $code;
0298      }
0299   
0300      /**
0301       * Adds the service return statement.
0302       *
0303       * @param string     $id         Service id
0304       * @param Definition $definition
0305       *
0306       * @return string
0307       */
0308      private function addServiceReturn($id, $definition)
0309      {
0310          if ($this->isSimpleInstance($id, $definition)) {
0311              return "    }\n";
0312          }
0313   
0314          return "\n        return \$instance;\n    }\n";
0315      }
0316   
0317      /**
0318       * Generates the service instance.
0319       *
0320       * @param string     $id
0321       * @param Definition $definition
0322       *
0323       * @return string
0324       *
0325       * @throws InvalidArgumentException
0326       * @throws RuntimeException
0327       */
0328      private function addServiceInstance($id, $definition)
0329      {
0330          $class = $this->dumpValue($definition->getClass());
0331   
0332          if (0 === strpos($class, "'") && !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
0333              throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
0334          }
0335   
0336          $simple           = $this->isSimpleInstance($id, $definition);
0337          $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
0338          $instantiation    = '';
0339   
0340          if (!$isProxyCandidate && ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) {
0341              $instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
0342          } elseif (!$isProxyCandidate && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
0343              $instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
0344          } elseif (!$simple) {
0345              $instantiation = '$instance';
0346          }
0347   
0348          $return = '';
0349          if ($simple) {
0350              $return = 'return ';
0351          } else {
0352              $instantiation .= ' = ';
0353          }
0354   
0355          $code = $this->addNewInstance($id, $definition, $return, $instantiation);
0356   
0357          if (!$simple) {
0358              $code .= "\n";
0359          }
0360   
0361          return $code;
0362      }
0363   
0364      /**
0365       * Checks if the definition is a simple instance.
0366       *
0367       * @param string     $id
0368       * @param Definition $definition
0369       *
0370       * @return bool
0371       */
0372      private function isSimpleInstance($id, $definition)
0373      {
0374          foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) {
0375              if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) {
0376                  continue;
0377              }
0378   
0379              if ($sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator()) {
0380                  return false;
0381              }
0382          }
0383   
0384          return true;
0385      }
0386   
0387      /**
0388       * Adds method calls to a service definition.
0389       *
0390       * @param string     $id
0391       * @param Definition $definition
0392       * @param string     $variableName
0393       *
0394       * @return string
0395       */
0396      private function addServiceMethodCalls($id, $definition, $variableName = 'instance')
0397      {
0398          $calls = '';
0399          foreach ($definition->getMethodCalls() as $call) {
0400              $arguments = array();
0401              foreach ($call[1] as $value) {
0402                  $arguments[] = $this->dumpValue($value);
0403              }
0404   
0405              $calls .= $this->wrapServiceConditionals($call[1], sprintf("        \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments)));
0406          }
0407   
0408          return $calls;
0409      }
0410   
0411      private function addServiceProperties($id, $definition, $variableName = 'instance')
0412      {
0413          $code = '';
0414          foreach ($definition->getProperties() as $name => $value) {
0415              $code .= sprintf("        \$%s->%s = %s;\n", $variableName, $name, $this->dumpValue($value));
0416          }
0417   
0418          return $code;
0419      }
0420   
0421      /**
0422       * Generates the inline definition setup.
0423       *
0424       * @param string     $id
0425       * @param Definition $definition
0426       *
0427       * @return string
0428       *
0429       * @throws ServiceCircularReferenceException when the container contains a circular reference
0430       */
0431      private function addServiceInlinedDefinitionsSetup($id, $definition)
0432      {
0433          $this->referenceVariables[$id] = new Variable('instance');
0434   
0435          $code = '';
0436          $processed = new \SplObjectStorage();
0437          foreach ($this->getInlinedDefinitions($definition) as $iDefinition) {
0438              if ($processed->contains($iDefinition)) {
0439                  continue;
0440              }
0441              $processed->offsetSet($iDefinition);
0442   
0443              if (!$this->hasReference($id, $iDefinition->getMethodCalls(), true) && !$this->hasReference($id, $iDefinition->getProperties(), true)) {
0444                  continue;
0445              }
0446   
0447              // if the instance is simple, the return statement has already been generated
0448              // so, the only possible way to get there is because of a circular reference
0449              if ($this->isSimpleInstance($id, $definition)) {
0450                  throw new ServiceCircularReferenceException($id, array($id));
0451              }
0452   
0453              $name = (string) $this->definitionVariables->offsetGet($iDefinition);
0454              $code .= $this->addServiceMethodCalls(null, $iDefinition, $name);
0455              $code .= $this->addServiceProperties(null, $iDefinition, $name);
0456              $code .= $this->addServiceConfigurator(null, $iDefinition, $name);
0457          }
0458   
0459          if ('' !== $code) {
0460              $code .= "\n";
0461          }
0462   
0463          return $code;
0464      }
0465   
0466      /**
0467       * Adds configurator definition
0468       *
0469       * @param string     $id
0470       * @param Definition $definition
0471       * @param string     $variableName
0472       *
0473       * @return string
0474       */
0475      private function addServiceConfigurator($id, $definition, $variableName = 'instance')
0476      {
0477          if (!$callable = $definition->getConfigurator()) {
0478              return '';
0479          }
0480   
0481          if (is_array($callable)) {
0482              if ($callable[0] instanceof Reference) {
0483                  return sprintf("        %s->%s(\$%s);\n", $this->getServiceCall((string) $callable[0]), $callable[1], $variableName);
0484              }
0485   
0486              return sprintf("        call_user_func(array(%s, '%s'), \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
0487          }
0488   
0489          return sprintf("        %s(\$%s);\n", $callable, $variableName);
0490      }
0491   
0492      /**
0493       * Adds a service
0494       *
0495       * @param string     $id
0496       * @param Definition $definition
0497       *
0498       * @return string
0499       */
0500      private function addService($id, $definition)
0501      {
0502          $this->definitionVariables = new \SplObjectStorage();
0503          $this->referenceVariables = array();
0504          $this->variableCount = 0;
0505   
0506          $return = array();
0507   
0508          if ($definition->isSynthetic()) {
0509              $return[] = '@throws RuntimeException always since this service is expected to be injected dynamically';
0510          } elseif ($class = $definition->getClass()) {
0511              $return[] = sprintf("@return %s A %s instance.", 0 === strpos($class, '%') ? 'object' : "\\".$class, $class);
0512          } elseif ($definition->getFactoryClass()) {
0513              $return[] = sprintf('@return object An instance returned by %s::%s().', $definition->getFactoryClass(), $definition->getFactoryMethod());
0514          } elseif ($definition->getFactoryService()) {
0515              $return[] = sprintf('@return object An instance returned by %s::%s().', $definition->getFactoryService(), $definition->getFactoryMethod());
0516          }
0517   
0518          $scope = $definition->getScope();
0519          if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
0520              if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
0521                  $return[] = '';
0522              }
0523              $return[] = sprintf("@throws InactiveScopeException when the '%s' service is requested while the '%s' scope is not active", $id, $scope);
0524          }
0525   
0526          $return = implode("\n     * ", $return);
0527   
0528          $doc = '';
0529          if (ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
0530              $doc .= <<<EOF
0531   
0532       *
0533       * This service is shared.
0534       * This method always returns the same instance of the service.
0535  EOF;
0536   
0537          }
0538   
0539          if (!$definition->isPublic()) {
0540              $doc .= <<<EOF
0541   
0542       *
0543       * This service is private.
0544       * If you want to be able to request this service from the container directly,
0545       * make it public, otherwise you might end up with broken code.
0546  EOF;
0547   
0548          }
0549   
0550          if ($definition->isLazy()) {
0551              $lazyInitialization    = '$lazyLoad = true';
0552              $lazyInitializationDoc = "\n     * @param bool    \$lazyLoad whether to try lazy-loading the service with a proxy\n     *";
0553          } else {
0554              $lazyInitialization    = '';
0555              $lazyInitializationDoc = '';
0556          }
0557   
0558          // with proxies, for 5.3.3 compatibility, the getter must be public to be accessible to the initializer
0559          $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
0560          $visibility       = $isProxyCandidate ? 'public' : 'protected';
0561          $code             = <<<EOF
0562   
0563      /**
0564       * Gets the '$id' service.$doc
0565       *$lazyInitializationDoc
0566       * $return
0567       */
0568      {$visibility} function get{$this->camelize($id)}Service($lazyInitialization)
0569      {
0570   
0571  EOF;
0572   
0573   
0574          $code .= $isProxyCandidate ? $this->getProxyDumper()->getProxyFactoryCode($definition, $id) : '';
0575   
0576          if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
0577              $code .= <<<EOF
0578          if (!isset(\$this->scopedServices['$scope'])) {
0579              throw new InactiveScopeException('$id', '$scope');
0580          }
0581   
0582   
0583  EOF;
0584   
0585          }
0586   
0587          if ($definition->isSynthetic()) {
0588              $code .= sprintf("        throw new RuntimeException('You have requested a synthetic service (\"%s\"). The DIC does not know how to construct this service.');\n    }\n", $id);
0589          } else {
0590              $code .=
0591                  $this->addServiceInclude($id, $definition).
0592                  $this->addServiceLocalTempVariables($id, $definition).
0593                  $this->addServiceInlinedDefinitions($id, $definition).
0594                  $this->addServiceInstance($id, $definition).
0595                  $this->addServiceInlinedDefinitionsSetup($id, $definition).
0596                  $this->addServiceMethodCalls($id, $definition).
0597                  $this->addServiceProperties($id, $definition).
0598                  $this->addServiceConfigurator($id, $definition).
0599                  $this->addServiceReturn($id, $definition)
0600              ;
0601          }
0602   
0603          $this->definitionVariables = null;
0604          $this->referenceVariables = null;
0605   
0606          return $code;
0607      }
0608   
0609      /**
0610       * Adds multiple services
0611       *
0612       * @return string
0613       */
0614      private function addServices()
0615      {
0616          $publicServices = $privateServices = $synchronizers = '';
0617          $definitions = $this->container->getDefinitions();
0618          ksort($definitions);
0619          foreach ($definitions as $id => $definition) {
0620              if ($definition->isPublic()) {
0621                  $publicServices .= $this->addService($id, $definition);
0622              } else {
0623                  $privateServices .= $this->addService($id, $definition);
0624              }
0625   
0626              $synchronizers .= $this->addServiceSynchronizer($id, $definition);
0627          }
0628   
0629          return $publicServices.$synchronizers.$privateServices;
0630      }
0631   
0632      /**
0633       * Adds synchronizer methods.
0634       *
0635       * @param string     $id         A service identifier
0636       * @param Definition $definition A Definition instance
0637       *
0638       * @return string|null
0639       */
0640      private function addServiceSynchronizer($id, Definition $definition)
0641      {
0642          if (!$definition->isSynchronized()) {
0643              return;
0644          }
0645   
0646          $code = '';
0647          foreach ($this->container->getDefinitions() as $definitionId => $definition) {
0648              foreach ($definition->getMethodCalls() as $call) {
0649                  foreach ($call[1] as $argument) {
0650                      if ($argument instanceof Reference && $id == (string) $argument) {
0651                          $arguments = array();
0652                          foreach ($call[1] as $value) {
0653                              $arguments[] = $this->dumpValue($value);
0654                          }
0655   
0656                          $call = $this->wrapServiceConditionals($call[1], sprintf("\$this->get('%s')->%s(%s);", $definitionId, $call[0], implode(', ', $arguments)));
0657   
0658                          $code .= <<<EOF
0659          if (\$this->initialized('$definitionId')) {
0660              $call
0661          }
0662   
0663  EOF;
0664   
0665                      }
0666                  }
0667              }
0668          }
0669   
0670          if (!$code) {
0671              return;
0672          }
0673   
0674          return <<<EOF
0675   
0676      /**
0677       * Updates the '$id' service.
0678       */
0679      protected function synchronize{$this->camelize($id)}Service()
0680      {
0681  $code    }
0682   
0683  EOF;
0684   
0685      }
0686   
0687      private function addNewInstance($id, Definition $definition, $return, $instantiation)
0688      {
0689          $class = $this->dumpValue($definition->getClass());
0690   
0691          $arguments = array();
0692          foreach ($definition->getArguments() as $value) {
0693              $arguments[] = $this->dumpValue($value);
0694          }
0695   
0696          if (null !== $definition->getFactoryMethod()) {
0697              if (null !== $definition->getFactoryClass()) {
0698                  return sprintf("        $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass()), $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : '');
0699              }
0700   
0701              if (null !== $definition->getFactoryService()) {
0702                  return sprintf("        $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService()), $definition->getFactoryMethod(), implode(', ', $arguments));
0703              }
0704   
0705              throw new RuntimeException(sprintf('Factory method requires a factory service or factory class in service definition for %s', $id));
0706          }
0707   
0708          if (false !== strpos($class, '$')) {
0709              return sprintf("        \$class = %s;\n\n        $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments));
0710          }
0711   
0712          return sprintf("        $return{$instantiation}new \\%s(%s);\n", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
0713      }
0714   
0715      /**
0716       * Adds the class headers.
0717       *
0718       * @param string $class     Class name
0719       * @param string $baseClass The name of the base class
0720       *
0721       * @return string
0722       */
0723      private function startClass($class, $baseClass)
0724      {
0725          $bagClass = $this->container->isFrozen() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;';
0726   
0727          return <<<EOF
0728  <?php
0729   
0730  use Symfony\Component\DependencyInjection\ContainerInterface;
0731  use Symfony\Component\DependencyInjection\Container;
0732  use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
0733  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
0734  use Symfony\Component\DependencyInjection\Exception\LogicException;
0735  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
0736  $bagClass
0737   
0738  /**
0739   * $class
0740   *
0741   * This class has been auto-generated
0742   * by the Symfony Dependency Injection Component.
0743   */
0744  class $class extends $baseClass
0745  {
0746  EOF;
0747   
0748      }
0749   
0750      /**
0751       * Adds the constructor.
0752       *
0753       * @return string
0754       */
0755      private function addConstructor()
0756      {
0757          $arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null;
0758   
0759          $code = <<<EOF
0760   
0761      /**
0762       * Constructor.
0763       */
0764      public function __construct()
0765      {
0766          parent::__construct($arguments);
0767   
0768  EOF;
0769   
0770   
0771          if (count($scopes = $this->container->getScopes()) > 0) {
0772              $code .= "\n";
0773              $code .= "        \$this->scopes = ".$this->dumpValue($scopes).";\n";
0774              $code .= "        \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
0775          }
0776   
0777          $code .= $this->addMethodMap();
0778          $code .= $this->addAliases();
0779   
0780          $code .= <<<EOF
0781      }
0782   
0783  EOF;
0784   
0785   
0786          return $code;
0787      }
0788   
0789      /**
0790       * Adds the constructor for a frozen container.
0791       *
0792       * @return string
0793       */
0794      private function addFrozenConstructor()
0795      {
0796          $code = <<<EOF
0797   
0798      /**
0799       * Constructor.
0800       */
0801      public function __construct()
0802      {
0803  EOF;
0804   
0805   
0806          if ($this->container->getParameterBag()->all()) {
0807              $code .= "\n        \$this->parameters = \$this->getDefaultParameters();\n";
0808          }
0809   
0810          $code .= <<<EOF
0811   
0812          \$this->services =
0813          \$this->scopedServices =
0814          \$this->scopeStacks = array();
0815   
0816          \$this->set('service_container', \$this);
0817   
0818  EOF;
0819   
0820   
0821          $code .= "\n";
0822          if (count($scopes = $this->container->getScopes()) > 0) {
0823              $code .= "        \$this->scopes = ".$this->dumpValue($scopes).";\n";
0824              $code .= "        \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
0825          } else {
0826              $code .= "        \$this->scopes = array();\n";
0827              $code .= "        \$this->scopeChildren = array();\n";
0828          }
0829   
0830          $code .= $this->addMethodMap();
0831          $code .= $this->addAliases();
0832   
0833          $code .= <<<EOF
0834      }
0835   
0836  EOF;
0837   
0838   
0839          return $code;
0840      }
0841   
0842      /**
0843       * Adds the methodMap property definition
0844       *
0845       * @return string
0846       */
0847      private function addMethodMap()
0848      {
0849          if (!$definitions = $this->container->getDefinitions()) {
0850              return '';
0851          }
0852   
0853          $code = "        \$this->methodMap = array(\n";
0854          ksort($definitions);
0855          foreach ($definitions as $id => $definition) {
0856              $code .= '            '.var_export($id, true).' => '.var_export('get'.$this->camelize($id).'Service', true).",\n";
0857          }
0858   
0859          return $code."        );\n";
0860      }
0861   
0862      /**
0863       * Adds the aliases property definition
0864       *
0865       * @return string
0866       */
0867      private function addAliases()
0868      {
0869          if (!$aliases = $this->container->getAliases()) {
0870              if ($this->container->isFrozen()) {
0871                  return "\n        \$this->aliases = array();\n";
0872              } else {
0873                  return '';
0874              }
0875          }
0876   
0877          $code = "        \$this->aliases = array(\n";
0878          ksort($aliases);
0879          foreach ($aliases as $alias => $id) {
0880              $id = (string) $id;
0881              while (isset($aliases[$id])) {
0882                  $id = (string) $aliases[$id];
0883              }
0884              $code .= '            '.var_export($alias, true).' => '.var_export($id, true).",\n";
0885          }
0886   
0887          return $code."        );\n";
0888      }
0889   
0890      /**
0891       * Adds default parameters method.
0892       *
0893       * @return string
0894       */
0895      private function addDefaultParametersMethod()
0896      {
0897          if (!$this->container->getParameterBag()->all()) {
0898              return '';
0899          }
0900   
0901          $parameters = $this->exportParameters($this->container->getParameterBag()->all());
0902   
0903          $code = '';
0904          if ($this->container->isFrozen()) {
0905              $code .= <<<EOF
0906   
0907      /**
0908       * {@inheritdoc}
0909       */
0910      public function getParameter(\$name)
0911      {
0912          \$name = strtolower(\$name);
0913   
0914          if (!(isset(\$this->parameters[\$name]) || array_key_exists(\$name, \$this->parameters))) {
0915              throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', \$name));
0916          }
0917   
0918          return \$this->parameters[\$name];
0919      }
0920   
0921      /**
0922       * {@inheritdoc}
0923       */
0924      public function hasParameter(\$name)
0925      {
0926          \$name = strtolower(\$name);
0927   
0928          return isset(\$this->parameters[\$name]) || array_key_exists(\$name, \$this->parameters);
0929      }
0930   
0931      /**
0932       * {@inheritdoc}
0933       */
0934      public function setParameter(\$name, \$value)
0935      {
0936          throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
0937      }
0938   
0939      /**
0940       * {@inheritdoc}
0941       */
0942      public function getParameterBag()
0943      {
0944          if (null === \$this->parameterBag) {
0945              \$this->parameterBag = new FrozenParameterBag(\$this->parameters);
0946          }
0947   
0948          return \$this->parameterBag;
0949      }
0950  EOF;
0951   
0952          }
0953   
0954          $code .= <<<EOF
0955   
0956      /**
0957       * Gets the default parameters.
0958       *
0959       * @return array An array of the default parameters
0960       */
0961      protected function getDefaultParameters()
0962      {
0963          return $parameters;
0964      }
0965   
0966  EOF;
0967   
0968   
0969          return $code;
0970      }
0971   
0972      /**
0973       * Exports parameters.
0974       *
0975       * @param array   $parameters
0976       * @param string  $path
0977       * @param int     $indent
0978       *
0979       * @return string
0980       *
0981       * @throws InvalidArgumentException
0982       */
0983      private function exportParameters($parameters, $path = '', $indent = 12)
0984      {
0985          $php = array();
0986          foreach ($parameters as $key => $value) {
0987              if (is_array($value)) {
0988                  $value = $this->exportParameters($value, $path.'/'.$key, $indent + 4);
0989              } elseif ($value instanceof Variable) {
0990                  throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".', $value, $path.'/'.$key));
0991              } elseif ($value instanceof Definition) {
0992                  throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain service definitions. Definition for "%s" found in "%s".', $value->getClass(), $path.'/'.$key));
0993              } elseif ($value instanceof Reference) {
0994                  throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain references to other services (reference to service "%s" found in "%s").', $value, $path.'/'.$key));
0995              } else {
0996                  $value = var_export($value, true);
0997              }
0998   
0999              $php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), var_export($key, true), $value);
1000          }
1001   
1002          return sprintf("array(\n%s\n%s)", implode("\n", $php), str_repeat(' ', $indent - 4));
1003      }
1004   
1005      /**
1006       * Ends the class definition.
1007       *
1008       * @return string
1009       */
1010      private function endClass()
1011      {
1012          return <<<EOF
1013  }
1014   
1015  EOF;
1016   
1017      }
1018   
1019      /**
1020       * Wraps the service conditionals.
1021       *
1022       * @param string $value
1023       * @param string $code
1024       *
1025       * @return string
1026       */
1027      private function wrapServiceConditionals($value, $code)
1028      {
1029          if (!$services = ContainerBuilder::getServiceConditionals($value)) {
1030              return $code;
1031          }
1032   
1033          $conditions = array();
1034          foreach ($services as $service) {
1035              $conditions[] = sprintf("\$this->has('%s')", $service);
1036          }
1037   
1038          // re-indent the wrapped code
1039          $code = implode("\n", array_map(function ($line) { return $line ? '    '.$line : $line; }, explode("\n", $code)));
1040   
1041          return sprintf("        if (%s) {\n%s        }\n", implode(' && ', $conditions), $code);
1042      }
1043   
1044      /**
1045       * Builds service calls from arguments.
1046       *
1047       * @param array  $arguments
1048       * @param array  &$calls    By reference
1049       * @param array  &$behavior By reference
1050       */
1051      private function getServiceCallsFromArguments(array $arguments, array &$calls, array &$behavior)
1052      {
1053          foreach ($arguments as $argument) {
1054              if (is_array($argument)) {
1055                  $this->getServiceCallsFromArguments($argument, $calls, $behavior);
1056              } elseif ($argument instanceof Reference) {
1057                  $id = (string) $argument;
1058   
1059                  if (!isset($calls[$id])) {
1060                      $calls[$id] = 0;
1061                  }
1062                  if (!isset($behavior[$id])) {
1063                      $behavior[$id] = $argument->getInvalidBehavior();
1064                  } elseif (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $behavior[$id]) {
1065                      $behavior[$id] = $argument->getInvalidBehavior();
1066                  }
1067   
1068                  $calls[$id] += 1;
1069              }
1070          }
1071      }
1072   
1073      /**
1074       * Returns the inline definition.
1075       *
1076       * @param Definition $definition
1077       *
1078       * @return array
1079       */
1080      private function getInlinedDefinitions(Definition $definition)
1081      {
1082          if (false === $this->inlinedDefinitions->contains($definition)) {
1083              $definitions = array_merge(
1084                  $this->getDefinitionsFromArguments($definition->getArguments()),
1085                  $this->getDefinitionsFromArguments($definition->getMethodCalls()),
1086                  $this->getDefinitionsFromArguments($definition->getProperties())
1087              );
1088   
1089              $this->inlinedDefinitions->offsetSet($definition, $definitions);
1090   
1091              return $definitions;
1092          }
1093   
1094          return $this->inlinedDefinitions->offsetGet($definition);
1095      }
1096   
1097      /**
1098       * Gets the definition from arguments.
1099       *
1100       * @param array $arguments
1101       *
1102       * @return array
1103       */
1104      private function getDefinitionsFromArguments(array $arguments)
1105      {
1106          $definitions = array();
1107          foreach ($arguments as $argument) {
1108              if (is_array($argument)) {
1109                  $definitions = array_merge($definitions, $this->getDefinitionsFromArguments($argument));
1110              } elseif ($argument instanceof Definition) {
1111                  $definitions = array_merge(
1112                      $definitions,
1113                      $this->getInlinedDefinitions($argument),
1114                      array($argument)
1115                  );
1116              }
1117          }
1118   
1119          return $definitions;
1120      }
1121   
1122      /**
1123       * Checks if a service id has a reference.
1124       *
1125       * @param string  $id
1126       * @param array   $arguments
1127       * @param bool    $deep
1128       * @param array   $visited
1129       *
1130       * @return bool
1131       */
1132      private function hasReference($id, array $arguments, $deep = false, $visited = array())
1133      {
1134          foreach ($arguments as $argument) {
1135              if (is_array($argument)) {
1136                  if ($this->hasReference($id, $argument, $deep, $visited)) {
1137                      return true;
1138                  }
1139              } elseif ($argument instanceof Reference) {
1140                  if ($id === (string) $argument) {
1141                      return true;
1142                  }
1143   
1144                  if ($deep && !isset($visited[(string) $argument])) {
1145                      $visited[(string) $argument] = true;
1146   
1147                      $service = $this->container->getDefinition((string) $argument);
1148                      $arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());
1149   
1150                      if ($this->hasReference($id, $arguments, $deep, $visited)) {
1151                          return true;
1152                      }
1153                  }
1154              }
1155          }
1156   
1157          return false;
1158      }
1159   
1160      /**
1161       * Dumps values.
1162       *
1163       * @param array   $value
1164       * @param bool    $interpolate
1165       *
1166       * @return string
1167       *
1168       * @throws RuntimeException
1169       */
1170      private function dumpValue($value, $interpolate = true)
1171      {
1172          if (is_array($value)) {
1173              $code = array();
1174              foreach ($value as $k => $v) {
1175                  $code[] = sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
1176              }
1177   
1178              return sprintf('array(%s)', implode(', ', $code));
1179          } elseif ($value instanceof Definition) {
1180              if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {
1181                  return $this->dumpValue($this->definitionVariables->offsetGet($value), $interpolate);
1182              }
1183              if (count($value->getMethodCalls()) > 0) {
1184                  throw new RuntimeException('Cannot dump definitions which have method calls.');
1185              }
1186              if (null !== $value->getConfigurator()) {
1187                  throw new RuntimeException('Cannot dump definitions which have a configurator.');
1188              }
1189   
1190              $arguments = array();
1191              foreach ($value->getArguments() as $argument) {
1192                  $arguments[] = $this->dumpValue($argument);
1193              }
1194              $class = $this->dumpValue($value->getClass());
1195   
1196              if (false !== strpos($class, '$')) {
1197                  throw new RuntimeException('Cannot dump definitions which have a variable class name.');
1198              }
1199   
1200              if (null !== $value->getFactoryMethod()) {
1201                  if (null !== $value->getFactoryClass()) {
1202                      return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($value->getFactoryClass()), $value->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1203                  } elseif (null !== $value->getFactoryService()) {
1204                      return sprintf("%s->%s(%s)", $this->getServiceCall($value->getFactoryService()), $value->getFactoryMethod(), implode(', ', $arguments));
1205                  } else {
1206                      throw new RuntimeException('Cannot dump definitions which have factory method without factory service or factory class.');
1207                  }
1208              }
1209   
1210              return sprintf("new \\%s(%s)", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
1211          } elseif ($value instanceof Variable) {
1212              return '$'.$value;
1213          } elseif ($value instanceof Reference) {
1214              if (null !== $this->referenceVariables && isset($this->referenceVariables[$id = (string) $value])) {
1215                  return $this->dumpValue($this->referenceVariables[$id], $interpolate);
1216              }
1217   
1218              return $this->getServiceCall((string) $value, $value);
1219          } elseif ($value instanceof Parameter) {
1220              return $this->dumpParameter($value);
1221          } elseif (true === $interpolate && is_string($value)) {
1222              if (preg_match('/^%([^%]+)%$/', $value, $match)) {
1223                  // we do this to deal with non string values (Boolean, integer, ...)
1224                  // the preg_replace_callback converts them to strings
1225                  return $this->dumpParameter(strtolower($match[1]));
1226              } else {
1227                  $that = $this;
1228                  $replaceParameters = function ($match) use ($that) {
1229                      return "'.".$that->dumpParameter(strtolower($match[2])).".'";
1230                  };
1231   
1232                  $code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, var_export($value, true)));
1233   
1234                  return $code;
1235              }
1236          } elseif (is_object($value) || is_resource($value)) {
1237              throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
1238          } else {
1239              return var_export($value, true);
1240          }
1241      }
1242   
1243      /**
1244       * Dumps a parameter
1245       *
1246       * @param string $name
1247       *
1248       * @return string
1249       */
1250      public function dumpParameter($name)
1251      {
1252          if ($this->container->isFrozen() && $this->container->hasParameter($name)) {
1253              return $this->dumpValue($this->container->getParameter($name), false);
1254          }
1255   
1256          return sprintf("\$this->getParameter('%s')", strtolower($name));
1257      }
1258   
1259      /**
1260       * Gets a service call
1261       *
1262       * @param string    $id
1263       * @param Reference $reference
1264       *
1265       * @return string
1266       */
1267      private function getServiceCall($id, Reference $reference = null)
1268      {
1269          if ('service_container' === $id) {
1270              return '$this';
1271          }
1272   
1273          if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
1274              return sprintf('$this->get(\'%s\', ContainerInterface::NULL_ON_INVALID_REFERENCE)', $id);
1275          } else {
1276              if ($this->container->hasAlias($id)) {
1277                  $id = (string) $this->container->getAlias($id);
1278              }
1279   
1280              return sprintf('$this->get(\'%s\')', $id);
1281          }
1282      }
1283   
1284      /**
1285       * Convert a service id to a valid PHP method name.
1286       *
1287       * @param string $id
1288       *
1289       * @return string
1290       *
1291       * @throws InvalidArgumentException
1292       */
1293      private function camelize($id)
1294      {
1295          $name = Container::camelize($id);
1296   
1297          if (!preg_match('/^[a-zA-Z0-9_\x7f-\xff]+$/', $name)) {
1298              throw new InvalidArgumentException(sprintf('Service id "%s" cannot be converted to a valid PHP method name.', $id));
1299          }
1300   
1301          return $name;
1302      }
1303   
1304      /**
1305       * Returns the next name to use
1306       *
1307       * @return string
1308       */
1309      private function getNextVariableName()
1310      {
1311          $firstChars = self::FIRST_CHARS;
1312          $firstCharsLength = strlen($firstChars);
1313          $nonFirstChars = self::NON_FIRST_CHARS;
1314          $nonFirstCharsLength = strlen($nonFirstChars);
1315   
1316          while (true) {
1317              $name = '';
1318              $i = $this->variableCount;
1319   
1320              if ('' === $name) {
1321                  $name .= $firstChars[$i%$firstCharsLength];
1322                  $i = intval($i/$firstCharsLength);
1323              }
1324   
1325              while ($i > 0) {
1326                  $i -= 1;
1327                  $name .= $nonFirstChars[$i%$nonFirstCharsLength];
1328                  $i = intval($i/$nonFirstCharsLength);
1329              }
1330   
1331              $this->variableCount += 1;
1332   
1333              // check that the name is not reserved
1334              if (in_array($name, $this->reservedVariables, true)) {
1335                  continue;
1336              }
1337   
1338              return $name;
1339          }
1340      }
1341  }
1342