Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
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: 02.04.2025, 15:03 - Dateigröße: 75.66 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\Argument\ArgumentInterface;
0015  use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
0016  use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
0017  use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
0018  use Symfony\Component\DependencyInjection\Compiler\CheckCircularReferencesPass;
0019  use Symfony\Component\DependencyInjection\Container;
0020  use Symfony\Component\DependencyInjection\ContainerBuilder;
0021  use Symfony\Component\DependencyInjection\ContainerInterface;
0022  use Symfony\Component\DependencyInjection\Definition;
0023  use Symfony\Component\DependencyInjection\Exception\EnvParameterException;
0024  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
0025  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
0026  use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
0027  use Symfony\Component\DependencyInjection\ExpressionLanguage;
0028  use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
0029  use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
0030  use Symfony\Component\DependencyInjection\Parameter;
0031  use Symfony\Component\DependencyInjection\Reference;
0032  use Symfony\Component\DependencyInjection\TypedReference;
0033  use Symfony\Component\DependencyInjection\Variable;
0034  use Symfony\Component\ExpressionLanguage\Expression;
0035  use Symfony\Component\HttpKernel\Kernel;
0036   
0037  /**
0038   * PhpDumper dumps a service container as a PHP class.
0039   *
0040   * @author Fabien Potencier <fabien@symfony.com>
0041   * @author Johannes M. Schmitt <schmittjoh@gmail.com>
0042   */
0043  class PhpDumper extends Dumper
0044  {
0045      /**
0046       * Characters that might appear in the generated variable name as first character.
0047       */
0048      const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz';
0049   
0050      /**
0051       * Characters that might appear in the generated variable name as any but the first character.
0052       */
0053      const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_';
0054   
0055      private $definitionVariables;
0056      private $referenceVariables;
0057      private $variableCount;
0058      private $inlinedDefinitions;
0059      private $serviceCalls;
0060      private $reservedVariables = ['instance', 'class', 'this'];
0061      private $expressionLanguage;
0062      private $targetDirRegex;
0063      private $targetDirMaxMatches;
0064      private $docStar;
0065      private $serviceIdToMethodNameMap;
0066      private $usedMethodNames;
0067      private $namespace;
0068      private $asFiles;
0069      private $hotPathTag;
0070      private $inlineRequires;
0071      private $inlinedRequires = [];
0072      private $circularReferences = [];
0073   
0074      /**
0075       * @var ProxyDumper
0076       */
0077      private $proxyDumper;
0078   
0079      /**
0080       * {@inheritdoc}
0081       */
0082      public function __construct(ContainerBuilder $container)
0083      {
0084          if (!$container->isCompiled()) {
0085              @trigger_error('Dumping an uncompiled ContainerBuilder is deprecated since Symfony 3.3 and will not be supported anymore in 4.0. Compile the container beforehand.', \E_USER_DEPRECATED);
0086          }
0087   
0088          parent::__construct($container);
0089      }
0090   
0091      /**
0092       * Sets the dumper to be used when dumping proxies in the generated container.
0093       */
0094      public function setProxyDumper(ProxyDumper $proxyDumper)
0095      {
0096          $this->proxyDumper = $proxyDumper;
0097      }
0098   
0099      /**
0100       * Dumps the service container as a PHP class.
0101       *
0102       * Available options:
0103       *
0104       *  * class:      The class name
0105       *  * base_class: The base class name
0106       *  * namespace:  The class namespace
0107       *  * as_files:   To split the container in several files
0108       *
0109       * @return string|array A PHP class representing the service container or an array of PHP files if the "as_files" option is set
0110       *
0111       * @throws EnvParameterException When an env var exists but has not been dumped
0112       */
0113      public function dump(array $options = [])
0114      {
0115          $this->targetDirRegex = null;
0116          $this->inlinedRequires = [];
0117          $options = array_merge([
0118              'class' => 'ProjectServiceContainer',
0119              'base_class' => 'Container',
0120              'namespace' => '',
0121              'as_files' => false,
0122              'debug' => true,
0123              'hot_path_tag' => 'container.hot_path',
0124              'inline_class_loader_parameter' => 'container.dumper.inline_class_loader',
0125              'build_time' => time(),
0126          ], $options);
0127   
0128          $this->namespace = $options['namespace'];
0129          $this->asFiles = $options['as_files'];
0130          $this->hotPathTag = $options['hot_path_tag'];
0131          $this->inlineRequires = $options['inline_class_loader_parameter'] && $this->container->hasParameter($options['inline_class_loader_parameter']) && $this->container->getParameter($options['inline_class_loader_parameter']);
0132   
0133          if (0 !== strpos($baseClass = $options['base_class'], '\\') && 'Container' !== $baseClass) {
0134              $baseClass = sprintf('%s\%s', $options['namespace'] ? '\\'.$options['namespace'] : '', $baseClass);
0135              $baseClassWithNamespace = $baseClass;
0136          } elseif ('Container' === $baseClass) {
0137              $baseClassWithNamespace = Container::class;
0138          } else {
0139              $baseClassWithNamespace = $baseClass;
0140          }
0141   
0142          $this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass);
0143   
0144          if ($this->getProxyDumper() instanceof NullDumper) {
0145              (new AnalyzeServiceReferencesPass(true, false))->process($this->container);
0146              try {
0147                  (new CheckCircularReferencesPass())->process($this->container);
0148              } catch (ServiceCircularReferenceException $e) {
0149                  $path = $e->getPath();
0150                  end($path);
0151                  $path[key($path)] .= '". Try running "composer require symfony/proxy-manager-bridge';
0152   
0153                  throw new ServiceCircularReferenceException($e->getServiceId(), $path);
0154              }
0155          }
0156   
0157          (new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
0158          $checkedNodes = [];
0159          $this->circularReferences = [];
0160          foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
0161              if (!$node->getValue() instanceof Definition) {
0162                  continue;
0163              }
0164              if (!isset($checkedNodes[$id])) {
0165                  $this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes);
0166              }
0167          }
0168          $this->container->getCompiler()->getServiceReferenceGraph()->clear();
0169          $checkedNodes = [];
0170   
0171          $this->docStar = $options['debug'] ? '*' : '';
0172   
0173          if (!empty($options['file']) && is_dir($dir = \dirname($options['file']))) {
0174              // Build a regexp where the first root dirs are mandatory,
0175              // but every other sub-dir is optional up to the full path in $dir
0176              // Mandate at least 1 root dir and not more than 5 optional dirs.
0177   
0178              $dir = explode(\DIRECTORY_SEPARATOR, realpath($dir));
0179              $i = \count($dir);
0180   
0181              if (2 + (int) ('\\' === \DIRECTORY_SEPARATOR) <= $i) {
0182                  $regex = '';
0183                  $lastOptionalDir = $i > 8 ? $i - 5 : (2 + (int) ('\\' === \DIRECTORY_SEPARATOR));
0184                  $this->targetDirMaxMatches = $i - $lastOptionalDir;
0185   
0186                  while (--$i >= $lastOptionalDir) {
0187                      $regex = sprintf('(%s%s)?', preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#'), $regex);
0188                  }
0189   
0190                  do {
0191                      $regex = preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#').$regex;
0192                  } while (0 < --$i);
0193   
0194                  $this->targetDirRegex = '#(^|file://|[:;, \|\r\n])'.preg_quote($dir[0], '#').$regex.'#';
0195              }
0196          }
0197   
0198          $code =
0199              $this->startClass($options['class'], $baseClass, $baseClassWithNamespace).
0200              $this->addServices().
0201              $this->addDefaultParametersMethod().
0202              $this->endClass()
0203          ;
0204   
0205          if ($this->asFiles) {
0206              $fileStart = <<<EOF
0207  <?php
0208   
0209  use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
0210   
0211  // This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
0212   
0213  EOF;
0214   
0215              $files = [];
0216   
0217              if ($ids = array_keys($this->container->getRemovedIds())) {
0218                  sort($ids);
0219                  $c = "<?php\n\nreturn [\n";
0220                  foreach ($ids as $id) {
0221                      $c .= '    '.$this->doExport($id)." => true,\n";
0222                  }
0223                  $files['removed-ids.php'] = $c."];\n";
0224              }
0225   
0226              foreach ($this->generateServiceFiles() as $file => $c) {
0227                  $files[$file] = $fileStart.$c;
0228              }
0229              foreach ($this->generateProxyClasses() as $file => $c) {
0230                  $files[$file] = "<?php\n".$c;
0231              }
0232              $files[$options['class'].'.php'] = $code;
0233              $hash = ucfirst(strtr(ContainerBuilder::hash($files), '._', 'xx'));
0234              $code = [];
0235   
0236              foreach ($files as $file => $c) {
0237                  $code["Container{$hash}/{$file}"] = $c;
0238              }
0239              array_pop($code);
0240              $code["Container{$hash}/{$options['class']}.php"] = substr_replace($files[$options['class'].'.php'], "<?php\n\nnamespace Container{$hash};\n", 0, 6);
0241              $namespaceLine = $this->namespace ? "\nnamespace {$this->namespace};\n" : '';
0242              $time = $options['build_time'];
0243              $id = hash('crc32', $hash.$time);
0244   
0245              $code[$options['class'].'.php'] = <<<EOF
0246  <?php
0247  {$namespaceLine}
0248  // This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
0249   
0250  if (\\class_exists(\\Container{$hash}\\{$options['class']}::class, false)) {
0251      // no-op
0252  } elseif (!include __DIR__.'/Container{$hash}/{$options['class']}.php') {
0253      touch(__DIR__.'/Container{$hash}.legacy');
0254   
0255      return;
0256  }
0257   
0258  if (!\\class_exists({$options['class']}::class, false)) {
0259      \\class_alias(\\Container{$hash}\\{$options['class']}::class, {$options['class']}::class, false);
0260  }
0261   
0262  return new \\Container{$hash}\\{$options['class']}([
0263      'container.build_hash' => '$hash',
0264      'container.build_id' => '$id',
0265      'container.build_time' => $time,
0266  ], __DIR__.\\DIRECTORY_SEPARATOR.'Container{$hash}');
0267   
0268  EOF;
0269   
0270          } else {
0271              foreach ($this->generateProxyClasses() as $c) {
0272                  $code .= $c;
0273              }
0274          }
0275   
0276          $this->targetDirRegex = null;
0277          $this->inlinedRequires = [];
0278          $this->circularReferences = [];
0279   
0280          $unusedEnvs = [];
0281          foreach ($this->container->getEnvCounters() as $env => $use) {
0282              if (!$use) {
0283                  $unusedEnvs[] = $env;
0284              }
0285          }
0286          if ($unusedEnvs) {
0287              throw new EnvParameterException($unusedEnvs, null, 'Environment variables "%s" are never used. Please, check your container\'s configuration.');
0288          }
0289   
0290          return $code;
0291      }
0292   
0293      /**
0294       * Retrieves the currently set proxy dumper or instantiates one.
0295       *
0296       * @return ProxyDumper
0297       */
0298      private function getProxyDumper()
0299      {
0300          if (!$this->proxyDumper) {
0301              $this->proxyDumper = new NullDumper();
0302          }
0303   
0304          return $this->proxyDumper;
0305      }
0306   
0307      private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = [], $byConstructor = true)
0308      {
0309          $checkedNodes[$sourceId] = true;
0310          $currentPath[$sourceId] = $byConstructor;
0311   
0312          foreach ($edges as $edge) {
0313              $node = $edge->getDestNode();
0314              $id = $node->getId();
0315   
0316              if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isLazy() || $edge->isWeak()) {
0317                  // no-op
0318              } elseif (isset($currentPath[$id])) {
0319                  $this->addCircularReferences($id, $currentPath, $edge->isReferencedByConstructor());
0320              } elseif (!isset($checkedNodes[$id])) {
0321                  $this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes, $currentPath, $edge->isReferencedByConstructor());
0322              } elseif (isset($this->circularReferences[$id])) {
0323                  $this->connectCircularReferences($id, $currentPath, $edge->isReferencedByConstructor());
0324              }
0325          }
0326          unset($currentPath[$sourceId]);
0327      }
0328   
0329      private function connectCircularReferences($sourceId, &$currentPath, $byConstructor, &$subPath = [])
0330      {
0331          $currentPath[$sourceId] = $subPath[$sourceId] = $byConstructor;
0332   
0333          foreach ($this->circularReferences[$sourceId] as $id => $byConstructor) {
0334              if (isset($currentPath[$id])) {
0335                  $this->addCircularReferences($id, $currentPath, $byConstructor);
0336              } elseif (!isset($subPath[$id]) && isset($this->circularReferences[$id])) {
0337                  $this->connectCircularReferences($id, $currentPath, $byConstructor, $subPath);
0338              }
0339          }
0340          unset($currentPath[$sourceId], $subPath[$sourceId]);
0341      }
0342   
0343      private function addCircularReferences($id, $currentPath, $byConstructor)
0344      {
0345          $currentPath[$id] = $byConstructor;
0346          $circularRefs = [];
0347   
0348          foreach (array_reverse($currentPath) as $parentId => $v) {
0349              $byConstructor = $byConstructor && $v;
0350              $circularRefs[] = $parentId;
0351   
0352              if ($parentId === $id) {
0353                  break;
0354              }
0355          }
0356   
0357          $currentId = $id;
0358          foreach ($circularRefs as $parentId) {
0359              if (empty($this->circularReferences[$parentId][$currentId])) {
0360                  $this->circularReferences[$parentId][$currentId] = $byConstructor;
0361              }
0362   
0363              $currentId = $parentId;
0364          }
0365      }
0366   
0367      private function collectLineage($class, array &$lineage)
0368      {
0369          if (isset($lineage[$class])) {
0370              return;
0371          }
0372          if (!$r = $this->container->getReflectionClass($class, false)) {
0373              return;
0374          }
0375          if ($this->container instanceof $class) {
0376              return;
0377          }
0378          $file = $r->getFileName();
0379          if (') : eval()\'d code' === substr($file, -17)) {
0380              $file = substr($file, 0, strrpos($file, '(', -17));
0381          }
0382          if (!$file || $this->doExport($file) === $exportedFile = $this->export($file)) {
0383              return;
0384          }
0385   
0386          if ($parent = $r->getParentClass()) {
0387              $this->collectLineage($parent->name, $lineage);
0388          }
0389   
0390          foreach ($r->getInterfaces() as $parent) {
0391              $this->collectLineage($parent->name, $lineage);
0392          }
0393   
0394          foreach ($r->getTraits() as $parent) {
0395              $this->collectLineage($parent->name, $lineage);
0396          }
0397   
0398          $lineage[$class] = substr($exportedFile, 1, -1);
0399      }
0400   
0401      private function generateProxyClasses()
0402      {
0403          $alreadyGenerated = [];
0404          $definitions = $this->container->getDefinitions();
0405          $strip = '' === $this->docStar && method_exists('Symfony\Component\HttpKernel\Kernel', 'stripComments');
0406          $proxyDumper = $this->getProxyDumper();
0407          ksort($definitions);
0408          foreach ($definitions as $definition) {
0409              if (!$proxyDumper->isProxyCandidate($definition)) {
0410                  continue;
0411              }
0412              if (isset($alreadyGenerated[$class = $definition->getClass()])) {
0413                  continue;
0414              }
0415              $alreadyGenerated[$class] = true;
0416              // register class' reflector for resource tracking
0417              $this->container->getReflectionClass($class);
0418              if ("\n" === $proxyCode = "\n".$proxyDumper->getProxyCode($definition)) {
0419                  continue;
0420              }
0421              if ($strip) {
0422                  $proxyCode = "<?php\n".$proxyCode;
0423                  $proxyCode = substr(Kernel::stripComments($proxyCode), 5);
0424              }
0425              yield sprintf('%s.php', explode(' ', $proxyCode, 3)[1]) => $proxyCode;
0426          }
0427      }
0428   
0429      /**
0430       * Generates the require_once statement for service includes.
0431       *
0432       * @return string
0433       */
0434      private function addServiceInclude($cId, Definition $definition)
0435      {
0436          $code = '';
0437   
0438          if ($this->inlineRequires && !$this->isHotPath($definition)) {
0439              $lineage = [];
0440              foreach ($this->inlinedDefinitions as $def) {
0441                  if (!$def->isDeprecated() && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
0442                      $this->collectLineage($class, $lineage);
0443                  }
0444              }
0445   
0446              foreach ($this->serviceCalls as $id => list($callCount, $behavior)) {
0447                  if ('service_container' !== $id && $id !== $cId
0448                      && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior
0449                      && $this->container->has($id)
0450                      && $this->isTrivialInstance($def = $this->container->findDefinition($id))
0451                      && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())
0452                  ) {
0453                      $this->collectLineage($class, $lineage);
0454                  }
0455              }
0456   
0457              foreach (array_diff_key(array_flip($lineage), $this->inlinedRequires) as $file => $class) {
0458                  $code .= sprintf("        include_once %s;\n", $file);
0459              }
0460          }
0461   
0462          foreach ($this->inlinedDefinitions as $def) {
0463              if ($file = $def->getFile()) {
0464                  $code .= sprintf("        include_once %s;\n", $this->dumpValue($file));
0465              }
0466          }
0467   
0468          if ('' !== $code) {
0469              $code .= "\n";
0470          }
0471   
0472          return $code;
0473      }
0474   
0475      /**
0476       * Generates the service instance.
0477       *
0478       * @param string $id
0479       * @param bool   $isSimpleInstance
0480       *
0481       * @return string
0482       *
0483       * @throws InvalidArgumentException
0484       * @throws RuntimeException
0485       */
0486      private function addServiceInstance($id, Definition $definition, $isSimpleInstance)
0487      {
0488          $class = $this->dumpValue($definition->getClass());
0489   
0490          if (0 === strpos($class, "'") && false === strpos($class, '$') && !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
0491              throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
0492          }
0493   
0494          $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
0495          $instantiation = '';
0496   
0497          if (!$isProxyCandidate && $definition->isShared()) {
0498              $instantiation = sprintf('$this->services[%s] = %s', $this->doExport($id), $isSimpleInstance ? '' : '$instance');
0499          } elseif (!$isSimpleInstance) {
0500              $instantiation = '$instance';
0501          }
0502   
0503          $return = '';
0504          if ($isSimpleInstance) {
0505              $return = 'return ';
0506          } else {
0507              $instantiation .= ' = ';
0508          }
0509   
0510          return $this->addNewInstance($definition, $return, $instantiation, $id);
0511      }
0512   
0513      /**
0514       * Checks if the definition is a trivial instance.
0515       *
0516       * @return bool
0517       */
0518      private function isTrivialInstance(Definition $definition)
0519      {
0520          if ($definition->isSynthetic() || $definition->getFile() || $definition->getMethodCalls() || $definition->getProperties() || $definition->getConfigurator()) {
0521              return false;
0522          }
0523          if ($definition->isDeprecated() || $definition->isLazy() || $definition->getFactory() || 3 < \count($definition->getArguments())) {
0524              return false;
0525          }
0526   
0527          foreach ($definition->getArguments() as $arg) {
0528              if (!$arg || $arg instanceof Parameter) {
0529                  continue;
0530              }
0531              if (\is_array($arg) && 3 >= \count($arg)) {
0532                  foreach ($arg as $k => $v) {
0533                      if ($this->dumpValue($k) !== $this->dumpValue($k, false)) {
0534                          return false;
0535                      }
0536                      if (!$v || $v instanceof Parameter) {
0537                          continue;
0538                      }
0539                      if ($v instanceof Reference && $this->container->has($id = (string) $v) && $this->container->findDefinition($id)->isSynthetic()) {
0540                          continue;
0541                      }
0542                      if (!is_scalar($v) || $this->dumpValue($v) !== $this->dumpValue($v, false)) {
0543                          return false;
0544                      }
0545                  }
0546              } elseif ($arg instanceof Reference && $this->container->has($id = (string) $arg) && $this->container->findDefinition($id)->isSynthetic()) {
0547                  continue;
0548              } elseif (!is_scalar($arg) || $this->dumpValue($arg) !== $this->dumpValue($arg, false)) {
0549                  return false;
0550              }
0551          }
0552   
0553          return true;
0554      }
0555   
0556      /**
0557       * Adds method calls to a service definition.
0558       *
0559       * @param string $variableName
0560       *
0561       * @return string
0562       */
0563      private function addServiceMethodCalls(Definition $definition, $variableName = 'instance')
0564      {
0565          $calls = '';
0566          foreach ($definition->getMethodCalls() as $call) {
0567              $arguments = [];
0568              foreach ($call[1] as $value) {
0569                  $arguments[] = $this->dumpValue($value);
0570              }
0571   
0572              $calls .= $this->wrapServiceConditionals($call[1], sprintf("        \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments)));
0573          }
0574   
0575          return $calls;
0576      }
0577   
0578      private function addServiceProperties(Definition $definition, $variableName = 'instance')
0579      {
0580          $code = '';
0581          foreach ($definition->getProperties() as $name => $value) {
0582              $code .= sprintf("        \$%s->%s = %s;\n", $variableName, $name, $this->dumpValue($value));
0583          }
0584   
0585          return $code;
0586      }
0587   
0588      /**
0589       * Adds configurator definition.
0590       *
0591       * @param string $variableName
0592       *
0593       * @return string
0594       */
0595      private function addServiceConfigurator(Definition $definition, $variableName = 'instance')
0596      {
0597          if (!$callable = $definition->getConfigurator()) {
0598              return '';
0599          }
0600   
0601          if (\is_array($callable)) {
0602              if ($callable[0] instanceof Reference
0603                  || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))
0604              ) {
0605                  return sprintf("        %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
0606              }
0607   
0608              $class = $this->dumpValue($callable[0]);
0609              // If the class is a string we can optimize call_user_func away
0610              if (0 === strpos($class, "'") && false === strpos($class, '$')) {
0611                  return sprintf("        %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $callable[1], $variableName);
0612              }
0613   
0614              if (0 === strpos($class, 'new ')) {
0615                  return sprintf("        (%s)->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
0616              }
0617   
0618              return sprintf("        \\call_user_func([%s, '%s'], \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
0619          }
0620   
0621          return sprintf("        %s(\$%s);\n", $callable, $variableName);
0622      }
0623   
0624      /**
0625       * Adds a service.
0626       *
0627       * @param string $id
0628       * @param string &$file
0629       *
0630       * @return string
0631       */
0632      private function addService($id, Definition $definition, &$file = null)
0633      {
0634          $this->definitionVariables = new \SplObjectStorage();
0635          $this->referenceVariables = [];
0636          $this->variableCount = 0;
0637          $this->referenceVariables[$id] = new Variable('instance');
0638   
0639          $return = [];
0640   
0641          if ($class = $definition->getClass()) {
0642              $class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class);
0643              $return[] = sprintf(0 === strpos($class, '%') ? '@return object A %1$s instance' : '@return \%s', ltrim($class, '\\'));
0644          } elseif ($definition->getFactory()) {
0645              $factory = $definition->getFactory();
0646              if (\is_string($factory)) {
0647                  $return[] = sprintf('@return object An instance returned by %s()', $factory);
0648              } elseif (\is_array($factory) && (\is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) {
0649                  $class = $factory[0] instanceof Definition ? $factory[0]->getClass() : (string) $factory[0];
0650                  $class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class);
0651                  $return[] = sprintf('@return object An instance returned by %s::%s()', $class, $factory[1]);
0652              }
0653          }
0654   
0655          if ($definition->isDeprecated()) {
0656              if ($return && 0 === strpos($return[\count($return) - 1], '@return')) {
0657                  $return[] = '';
0658              }
0659   
0660              $return[] = sprintf('@deprecated %s', $definition->getDeprecationMessage($id));
0661          }
0662   
0663          $return = str_replace("\n     * \n", "\n     *\n", implode("\n     * ", $return));
0664          $return = $this->container->resolveEnvPlaceholders($return);
0665   
0666          $shared = $definition->isShared() ? ' shared' : '';
0667          $public = $definition->isPublic() ? 'public' : 'private';
0668          $autowired = $definition->isAutowired() ? ' autowired' : '';
0669   
0670          if ($definition->isLazy()) {
0671              $lazyInitialization = '$lazyLoad = true';
0672          } else {
0673              $lazyInitialization = '';
0674          }
0675   
0676          $asFile = $this->asFiles && $definition->isShared() && !$this->isHotPath($definition);
0677          $methodName = $this->generateMethodName($id);
0678          if ($asFile) {
0679              $file = $methodName.'.php';
0680              $code = "        // Returns the $public '$id'$shared$autowired service.\n\n";
0681          } else {
0682              $code = <<<EOF
0683   
0684      /*{$this->docStar}
0685       * Gets the $public '$id'$shared$autowired service.
0686       *
0687       * $return
0688  EOF;
0689   
0690              $code = str_replace('*/', ' ', $code).<<<EOF
0691   
0692       */
0693      protected function {$methodName}($lazyInitialization)
0694      {
0695   
0696  EOF;
0697   
0698          }
0699   
0700          $this->serviceCalls = [];
0701          $this->inlinedDefinitions = $this->getDefinitionsFromArguments([$definition], null, $this->serviceCalls);
0702   
0703          $code .= $this->addServiceInclude($id, $definition);
0704   
0705          if ($this->getProxyDumper()->isProxyCandidate($definition)) {
0706              $factoryCode = $asFile ? "\$this->load('%s.php', false)" : '$this->%s(false)';
0707              $code .= $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName, $this->doExport($id)));
0708          }
0709   
0710          if ($definition->isDeprecated()) {
0711              $code .= sprintf("        @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id)));
0712          }
0713   
0714          $code .= $this->addInlineService($id, $definition);
0715   
0716          if ($asFile) {
0717              $code = implode("\n", array_map(function ($line) { return $line ? substr($line, 8) : $line; }, explode("\n", $code)));
0718          } else {
0719              $code .= "    }\n";
0720          }
0721   
0722          $this->definitionVariables = $this->inlinedDefinitions = null;
0723          $this->referenceVariables = $this->serviceCalls = null;
0724   
0725          return $code;
0726      }
0727   
0728      private function addInlineVariables($id, Definition $definition, array $arguments, $forConstructor)
0729      {
0730          $code = '';
0731   
0732          foreach ($arguments as $argument) {
0733              if (\is_array($argument)) {
0734                  $code .= $this->addInlineVariables($id, $definition, $argument, $forConstructor);
0735              } elseif ($argument instanceof Reference) {
0736                  $code .= $this->addInlineReference($id, $definition, $this->container->normalizeId($argument), $forConstructor);
0737              } elseif ($argument instanceof Definition) {
0738                  $code .= $this->addInlineService($id, $definition, $argument, $forConstructor);
0739              }
0740          }
0741   
0742          return $code;
0743      }
0744   
0745      private function addInlineReference($id, Definition $definition, $targetId, $forConstructor)
0746      {
0747          while ($this->container->hasAlias($targetId)) {
0748              $targetId = (string) $this->container->getAlias($targetId);
0749          }
0750   
0751          list($callCount, $behavior) = $this->serviceCalls[$targetId];
0752   
0753          if ($id === $targetId) {
0754              return $this->addInlineService($id, $definition, $definition);
0755          }
0756   
0757          if ('service_container' === $targetId || isset($this->referenceVariables[$targetId])) {
0758              return '';
0759          }
0760   
0761          $hasSelfRef = isset($this->circularReferences[$id][$targetId]) && !isset($this->definitionVariables[$definition]);
0762   
0763          if ($hasSelfRef && !$forConstructor && !$forConstructor = !$this->circularReferences[$id][$targetId]) {
0764              $code = $this->addInlineService($id, $definition, $definition);
0765          } else {
0766              $code = '';
0767          }
0768   
0769          if (isset($this->referenceVariables[$targetId]) || (2 > $callCount && (!$hasSelfRef || !$forConstructor))) {
0770              return $code;
0771          }
0772   
0773          $name = $this->getNextVariableName();
0774          $this->referenceVariables[$targetId] = new Variable($name);
0775   
0776          $reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $behavior ? new Reference($targetId, $behavior) : null;
0777          $code .= sprintf("        \$%s = %s;\n", $name, $this->getServiceCall($targetId, $reference));
0778   
0779          if (!$hasSelfRef || !$forConstructor) {
0780              return $code;
0781          }
0782   
0783          $code .= sprintf(<<<'EOTXT'
0784   
0785          if (isset($this->%s[%s])) {
0786              return $this->%1$s[%2$s];
0787          }
0788   
0789  EOTXT
0790              ,
0791              'services',
0792              $this->doExport($id)
0793          );
0794   
0795          return $code;
0796      }
0797   
0798      private function addInlineService($id, Definition $definition, Definition $inlineDef = null, $forConstructor = true)
0799      {
0800          $code = '';
0801   
0802          if ($isSimpleInstance = $isRootInstance = null === $inlineDef) {
0803              foreach ($this->serviceCalls as $targetId => list($callCount, $behavior, $byConstructor)) {
0804                  if ($byConstructor && isset($this->circularReferences[$id][$targetId]) && !$this->circularReferences[$id][$targetId]) {
0805                      $code .= $this->addInlineReference($id, $definition, $targetId, $forConstructor);
0806                  }
0807              }
0808          }
0809   
0810          if (isset($this->definitionVariables[$inlineDef = $inlineDef ?: $definition])) {
0811              return $code;
0812          }
0813   
0814          $arguments = [$inlineDef->getArguments(), $inlineDef->getFactory()];
0815   
0816          $code .= $this->addInlineVariables($id, $definition, $arguments, $forConstructor);
0817   
0818          if ($arguments = array_filter([$inlineDef->getProperties(), $inlineDef->getMethodCalls(), $inlineDef->getConfigurator()])) {
0819              $isSimpleInstance = false;
0820          } elseif ($definition !== $inlineDef && 2 > $this->inlinedDefinitions[$inlineDef]) {
0821              return $code;
0822          }
0823   
0824          if (isset($this->definitionVariables[$inlineDef])) {
0825              $isSimpleInstance = false;
0826          } else {
0827              $name = $definition === $inlineDef ? 'instance' : $this->getNextVariableName();
0828              $this->definitionVariables[$inlineDef] = new Variable($name);
0829              $code .= '' !== $code ? "\n" : '';
0830   
0831              if ('instance' === $name) {
0832                  $code .= $this->addServiceInstance($id, $definition, $isSimpleInstance);
0833              } else {
0834                  $code .= $this->addNewInstance($inlineDef, '$'.$name, ' = ', $id);
0835              }
0836   
0837              if ('' !== $inline = $this->addInlineVariables($id, $definition, $arguments, false)) {
0838                  $code .= "\n".$inline."\n";
0839              } elseif ($arguments && 'instance' === $name) {
0840                  $code .= "\n";
0841              }
0842   
0843              $code .= $this->addServiceProperties($inlineDef, $name);
0844              $code .= $this->addServiceMethodCalls($inlineDef, $name);
0845              $code .= $this->addServiceConfigurator($inlineDef, $name);
0846          }
0847   
0848          if ($isRootInstance && !$isSimpleInstance) {
0849              $code .= "\n        return \$instance;\n";
0850          }
0851   
0852          return $code;
0853      }
0854   
0855      /**
0856       * Adds multiple services.
0857       *
0858       * @return string
0859       */
0860      private function addServices()
0861      {
0862          $publicServices = $privateServices = '';
0863          $definitions = $this->container->getDefinitions();
0864          ksort($definitions);
0865          foreach ($definitions as $id => $definition) {
0866              if ($definition->isSynthetic() || ($this->asFiles && $definition->isShared() && !$this->isHotPath($definition))) {
0867                  continue;
0868              }
0869              if ($definition->isPublic()) {
0870                  $publicServices .= $this->addService($id, $definition);
0871              } else {
0872                  $privateServices .= $this->addService($id, $definition);
0873              }
0874          }
0875   
0876          return $publicServices.$privateServices;
0877      }
0878   
0879      private function generateServiceFiles()
0880      {
0881          $definitions = $this->container->getDefinitions();
0882          ksort($definitions);
0883          foreach ($definitions as $id => $definition) {
0884              if (!$definition->isSynthetic() && $definition->isShared() && !$this->isHotPath($definition)) {
0885                  $code = $this->addService($id, $definition, $file);
0886                  yield $file => $code;
0887              }
0888          }
0889      }
0890   
0891      private function addNewInstance(Definition $definition, $return, $instantiation, $id)
0892      {
0893          $class = $this->dumpValue($definition->getClass());
0894          $return = '        '.$return.$instantiation;
0895   
0896          $arguments = [];
0897          foreach ($definition->getArguments() as $value) {
0898              $arguments[] = $this->dumpValue($value);
0899          }
0900   
0901          if (null !== $definition->getFactory()) {
0902              $callable = $definition->getFactory();
0903              if (\is_array($callable)) {
0904                  if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) {
0905                      throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s).', $callable[1] ?: 'n/a'));
0906                  }
0907   
0908                  if ($callable[0] instanceof Reference
0909                      || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
0910                      return $return.sprintf("%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '');
0911                  }
0912   
0913                  $class = $this->dumpValue($callable[0]);
0914                  // If the class is a string we can optimize call_user_func away
0915                  if (0 === strpos($class, "'") && false === strpos($class, '$')) {
0916                      if ("''" === $class) {
0917                          throw new RuntimeException(sprintf('Cannot dump definition: The "%s" service is defined to be created by a factory but is missing the service reference, did you forget to define the factory service id or class?', $id));
0918                      }
0919   
0920                      return $return.sprintf("%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '');
0921                  }
0922   
0923                  if (0 === strpos($class, 'new ')) {
0924                      return $return.sprintf("(%s)->%s(%s);\n", $class, $callable[1], $arguments ? implode(', ', $arguments) : '');
0925                  }
0926   
0927                  return $return.sprintf("\\call_user_func([%s, '%s']%s);\n", $class, $callable[1], $arguments ? ', '.implode(', ', $arguments) : '');
0928              }
0929   
0930              return $return.sprintf("%s(%s);\n", $this->dumpLiteralClass($this->dumpValue($callable)), $arguments ? implode(', ', $arguments) : '');
0931          }
0932   
0933          if (false !== strpos($class, '$')) {
0934              return sprintf("        \$class = %s;\n\n%snew \$class(%s);\n", $class, $return, implode(', ', $arguments));
0935          }
0936   
0937          return $return.sprintf("new %s(%s);\n", $this->dumpLiteralClass($class), implode(', ', $arguments));
0938      }
0939   
0940      /**
0941       * Adds the class headers.
0942       *
0943       * @param string $class                  Class name
0944       * @param string $baseClass              The name of the base class
0945       * @param string $baseClassWithNamespace Fully qualified base class name
0946       *
0947       * @return string
0948       */
0949      private function startClass($class, $baseClass, $baseClassWithNamespace)
0950      {
0951          $bagClass = $this->container->isCompiled() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;';
0952          $namespaceLine = !$this->asFiles && $this->namespace ? "\nnamespace {$this->namespace};\n" : '';
0953   
0954          $code = <<<EOF
0955  <?php
0956  $namespaceLine
0957  use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
0958  use Symfony\Component\DependencyInjection\ContainerInterface;
0959  use Symfony\Component\DependencyInjection\Container;
0960  use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
0961  use Symfony\Component\DependencyInjection\Exception\LogicException;
0962  use Symfony\Component\DependencyInjection\Exception\RuntimeException;
0963  $bagClass
0964   
0965  /*{$this->docStar}
0966   * This class has been auto-generated
0967   * by the Symfony Dependency Injection Component.
0968   *
0969   * @final since Symfony 3.3
0970   */
0971  class $class extends $baseClass
0972  {
0973      private \$parameters = [];
0974      private \$targetDirs = [];
0975   
0976      public function __construct()
0977      {
0978   
0979  EOF;
0980   
0981          if (null !== $this->targetDirRegex) {
0982              $dir = $this->asFiles ? '$this->targetDirs[0] = \\dirname($containerDir)' : '__DIR__';
0983              $code .= <<<EOF
0984          \$dir = {$dir};
0985          for (\$i = 1; \$i <= {$this->targetDirMaxMatches}; ++\$i) {
0986              \$this->targetDirs[\$i] = \$dir = \\dirname(\$dir);
0987          }
0988   
0989  EOF;
0990   
0991          }
0992          if ($this->asFiles) {
0993              $code = str_replace('$parameters', "\$buildParameters;\n    private \$containerDir;\n    private \$parameters", $code);
0994              $code = str_replace('__construct()', '__construct(array $buildParameters = [], $containerDir = __DIR__)', $code);
0995              $code .= "        \$this->buildParameters = \$buildParameters;\n";
0996              $code .= "        \$this->containerDir = \$containerDir;\n";
0997          }
0998   
0999          if ($this->container->isCompiled()) {
1000              if (Container::class !== $baseClassWithNamespace) {
1001                  $r = $this->container->getReflectionClass($baseClassWithNamespace, false);
1002                  if (null !== $r
1003                      && (null !== $constructor = $r->getConstructor())
1004                      && 0 === $constructor->getNumberOfRequiredParameters()
1005                      && Container::class !== $constructor->getDeclaringClass()->name
1006                  ) {
1007                      $code .= "        parent::__construct();\n";
1008                      $code .= "        \$this->parameterBag = null;\n\n";
1009                  }
1010              }
1011   
1012              if ($this->container->getParameterBag()->all()) {
1013                  $code .= "        \$this->parameters = \$this->getDefaultParameters();\n\n";
1014              }
1015   
1016              $code .= "        \$this->services = [];\n";
1017          } else {
1018              $arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null;
1019              $code .= "        parent::__construct($arguments);\n";
1020          }
1021   
1022          $code .= $this->addNormalizedIds();
1023          $code .= $this->addSyntheticIds();
1024          $code .= $this->addMethodMap();
1025          $code .= $this->asFiles ? $this->addFileMap() : '';
1026          $code .= $this->addPrivateServices();
1027          $code .= $this->addAliases();
1028          $code .= $this->addInlineRequires();
1029          $code .= <<<'EOF'
1030      }
1031   
1032  EOF;
1033   
1034          $code .= $this->addRemovedIds();
1035   
1036          if ($this->container->isCompiled()) {
1037              $code .= <<<EOF
1038   
1039      public function compile()
1040      {
1041          throw new LogicException('You cannot compile a dumped container that was already compiled.');
1042      }
1043   
1044      public function isCompiled()
1045      {
1046          return true;
1047      }
1048   
1049      public function isFrozen()
1050      {
1051          @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED);
1052   
1053          return true;
1054      }
1055   
1056  EOF;
1057   
1058          }
1059   
1060          if ($this->asFiles) {
1061              $code .= <<<EOF
1062   
1063      protected function load(\$file, \$lazyLoad = true)
1064      {
1065          return require \$this->containerDir.\\DIRECTORY_SEPARATOR.\$file;
1066      }
1067   
1068  EOF;
1069   
1070          }
1071   
1072          $proxyDumper = $this->getProxyDumper();
1073          foreach ($this->container->getDefinitions() as $definition) {
1074              if (!$proxyDumper->isProxyCandidate($definition)) {
1075                  continue;
1076              }
1077              if ($this->asFiles) {
1078                  $proxyLoader = '$this->load("{$class}.php")';
1079              } elseif ($this->namespace) {
1080                  $proxyLoader = 'class_alias("'.$this->namespace.'\\\\{$class}", $class, false)';
1081              } else {
1082                  $proxyLoader = '';
1083              }
1084              if ($proxyLoader) {
1085                  $proxyLoader = "class_exists(\$class, false) || {$proxyLoader};\n\n        ";
1086              }
1087              $code .= <<<EOF
1088   
1089      protected function createProxy(\$class, \Closure \$factory)
1090      {
1091          {$proxyLoader}return \$factory();
1092      }
1093   
1094  EOF;
1095   
1096              break;
1097          }
1098   
1099          return $code;
1100      }
1101   
1102      /**
1103       * Adds the normalizedIds property definition.
1104       *
1105       * @return string
1106       */
1107      private function addNormalizedIds()
1108      {
1109          $code = '';
1110          $normalizedIds = $this->container->getNormalizedIds();
1111          ksort($normalizedIds);
1112          foreach ($normalizedIds as $id => $normalizedId) {
1113              if ($this->container->has($normalizedId)) {
1114                  $code .= '            '.$this->doExport($id).' => '.$this->doExport($normalizedId).",\n";
1115              }
1116          }
1117   
1118          return $code ? "        \$this->normalizedIds = [\n".$code."        ];\n" : '';
1119      }
1120   
1121      /**
1122       * Adds the syntheticIds definition.
1123       *
1124       * @return string
1125       */
1126      private function addSyntheticIds()
1127      {
1128          $code = '';
1129          $definitions = $this->container->getDefinitions();
1130          ksort($definitions);
1131          foreach ($definitions as $id => $definition) {
1132              if ($definition->isSynthetic() && 'service_container' !== $id) {
1133                  $code .= '            '.$this->doExport($id)." => true,\n";
1134              }
1135          }
1136   
1137          return $code ? "        \$this->syntheticIds = [\n{$code}        ];\n" : '';
1138      }
1139   
1140      /**
1141       * Adds the removedIds definition.
1142       *
1143       * @return string
1144       */
1145      private function addRemovedIds()
1146      {
1147          if (!$ids = $this->container->getRemovedIds()) {
1148              return '';
1149          }
1150          if ($this->asFiles) {
1151              $code = "require \$this->containerDir.\\DIRECTORY_SEPARATOR.'removed-ids.php'";
1152          } else {
1153              $code = '';
1154              $ids = array_keys($ids);
1155              sort($ids);
1156              foreach ($ids as $id) {
1157                  if (preg_match('/^\d+_[^~]++~[._a-zA-Z\d]{7}$/', $id)) {
1158                      continue;
1159                  }
1160                  $code .= '            '.$this->doExport($id)." => true,\n";
1161              }
1162   
1163              $code = "[\n{$code}        ]";
1164          }
1165   
1166          return <<<EOF
1167   
1168      public function getRemovedIds()
1169      {
1170          return {$code};
1171      }
1172   
1173  EOF;
1174   
1175      }
1176   
1177      /**
1178       * Adds the methodMap property definition.
1179       *
1180       * @return string
1181       */
1182      private function addMethodMap()
1183      {
1184          $code = '';
1185          $definitions = $this->container->getDefinitions();
1186          ksort($definitions);
1187          foreach ($definitions as $id => $definition) {
1188              if (!$definition->isSynthetic() && (!$this->asFiles || !$definition->isShared() || $this->isHotPath($definition))) {
1189                  $code .= '            '.$this->doExport($id).' => '.$this->doExport($this->generateMethodName($id)).",\n";
1190              }
1191          }
1192   
1193          return $code ? "        \$this->methodMap = [\n{$code}        ];\n" : '';
1194      }
1195   
1196      /**
1197       * Adds the fileMap property definition.
1198       *
1199       * @return string
1200       */
1201      private function addFileMap()
1202      {
1203          $code = '';
1204          $definitions = $this->container->getDefinitions();
1205          ksort($definitions);
1206          foreach ($definitions as $id => $definition) {
1207              if (!$definition->isSynthetic() && $definition->isShared() && !$this->isHotPath($definition)) {
1208                  $code .= sprintf("            %s => '%s.php',\n", $this->doExport($id), $this->generateMethodName($id));
1209              }
1210          }
1211   
1212          return $code ? "        \$this->fileMap = [\n{$code}        ];\n" : '';
1213      }
1214   
1215      /**
1216       * Adds the privates property definition.
1217       *
1218       * @return string
1219       */
1220      private function addPrivateServices()
1221      {
1222          $code = '';
1223   
1224          $aliases = $this->container->getAliases();
1225          ksort($aliases);
1226          foreach ($aliases as $id => $alias) {
1227              if ($alias->isPrivate()) {
1228                  $code .= '            '.$this->doExport($id)." => true,\n";
1229              }
1230          }
1231   
1232          $definitions = $this->container->getDefinitions();
1233          ksort($definitions);
1234          foreach ($definitions as $id => $definition) {
1235              if (!$definition->isPublic()) {
1236                  $code .= '            '.$this->doExport($id)." => true,\n";
1237              }
1238          }
1239   
1240          if (empty($code)) {
1241              return '';
1242          }
1243   
1244          $out = "        \$this->privates = [\n";
1245          $out .= $code;
1246          $out .= "        ];\n";
1247   
1248          return $out;
1249      }
1250   
1251      /**
1252       * Adds the aliases property definition.
1253       *
1254       * @return string
1255       */
1256      private function addAliases()
1257      {
1258          if (!$aliases = $this->container->getAliases()) {
1259              return $this->container->isCompiled() ? "\n        \$this->aliases = [];\n" : '';
1260          }
1261   
1262          $code = "        \$this->aliases = [\n";
1263          ksort($aliases);
1264          foreach ($aliases as $alias => $id) {
1265              $id = $this->container->normalizeId($id);
1266              while (isset($aliases[$id])) {
1267                  $id = $this->container->normalizeId($aliases[$id]);
1268              }
1269              $code .= '            '.$this->doExport($alias).' => '.$this->doExport($id).",\n";
1270          }
1271   
1272          return $code."        ];\n";
1273      }
1274   
1275      private function addInlineRequires()
1276      {
1277          if (!$this->hotPathTag || !$this->inlineRequires) {
1278              return '';
1279          }
1280   
1281          $lineage = [];
1282   
1283          foreach ($this->container->findTaggedServiceIds($this->hotPathTag) as $id => $tags) {
1284              $definition = $this->container->getDefinition($id);
1285              $inlinedDefinitions = $this->getDefinitionsFromArguments([$definition]);
1286   
1287              foreach ($inlinedDefinitions as $def) {
1288                  if (\is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
1289                      $this->collectLineage($class, $lineage);
1290                  }
1291              }
1292          }
1293   
1294          $code = '';
1295   
1296          foreach ($lineage as $file) {
1297              if (!isset($this->inlinedRequires[$file])) {
1298                  $this->inlinedRequires[$file] = true;
1299                  $code .= sprintf("\n            include_once %s;", $file);
1300              }
1301          }
1302   
1303          return $code ? sprintf("\n        \$this->privates['service_container'] = function () {%s\n        };\n", $code) : '';
1304      }
1305   
1306      /**
1307       * Adds default parameters method.
1308       *
1309       * @return string
1310       */
1311      private function addDefaultParametersMethod()
1312      {
1313          if (!$this->container->getParameterBag()->all()) {
1314              return '';
1315          }
1316   
1317          $php = [];
1318          $dynamicPhp = [];
1319          $normalizedParams = [];
1320   
1321          foreach ($this->container->getParameterBag()->all() as $key => $value) {
1322              if ($key !== $resolvedKey = $this->container->resolveEnvPlaceholders($key)) {
1323                  throw new InvalidArgumentException(sprintf('Parameter name cannot use env parameters: "%s".', $resolvedKey));
1324              }
1325              if ($key !== $lcKey = strtolower($key)) {
1326                  $normalizedParams[] = sprintf('        %s => %s,', $this->export($lcKey), $this->export($key));
1327              }
1328              $export = $this->exportParameters([$value]);
1329              $export = explode('0 => ', substr(rtrim($export, " ]\n"), 2, -1), 2);
1330   
1331              if (preg_match("/\\\$this->(?:getEnv\('(?:\w++:)*+\w++'\)|targetDirs\[\d++\])/", $export[1])) {
1332                  $dynamicPhp[$key] = sprintf('%scase %s: $value = %s; break;', $export[0], $this->export($key), $export[1]);
1333              } else {
1334                  $php[] = sprintf('%s%s => %s,', $export[0], $this->export($key), $export[1]);
1335              }
1336          }
1337   
1338          $parameters = sprintf("[\n%s\n%s]", implode("\n", $php), str_repeat(' ', 8));
1339   
1340          $code = '';
1341          if ($this->container->isCompiled()) {
1342              $code .= <<<'EOF'
1343   
1344      public function getParameter($name)
1345      {
1346          $name = (string) $name;
1347          if (isset($this->buildParameters[$name])) {
1348              return $this->buildParameters[$name];
1349          }
1350          if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
1351              $name = $this->normalizeParameterName($name);
1352   
1353              if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
1354                  throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
1355              }
1356          }
1357          if (isset($this->loadedDynamicParameters[$name])) {
1358              return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
1359          }
1360   
1361          return $this->parameters[$name];
1362      }
1363   
1364      public function hasParameter($name)
1365      {
1366          $name = (string) $name;
1367          if (isset($this->buildParameters[$name])) {
1368              return true;
1369          }
1370          $name = $this->normalizeParameterName($name);
1371   
1372          return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
1373      }
1374   
1375      public function setParameter($name, $value)
1376      {
1377          throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
1378      }
1379   
1380      public function getParameterBag()
1381      {
1382          if (null === $this->parameterBag) {
1383              $parameters = $this->parameters;
1384              foreach ($this->loadedDynamicParameters as $name => $loaded) {
1385                  $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
1386              }
1387              foreach ($this->buildParameters as $name => $value) {
1388                  $parameters[$name] = $value;
1389              }
1390              $this->parameterBag = new FrozenParameterBag($parameters);
1391          }
1392   
1393          return $this->parameterBag;
1394      }
1395   
1396  EOF;
1397   
1398              if (!$this->asFiles) {
1399                  $code = preg_replace('/^.*buildParameters.*\n.*\n.*\n/m', '', $code);
1400              }
1401   
1402              if ($dynamicPhp) {
1403                  $loadedDynamicParameters = $this->exportParameters(array_combine(array_keys($dynamicPhp), array_fill(0, \count($dynamicPhp), false)), '', 8);
1404                  $getDynamicParameter = <<<'EOF'
1405          switch ($name) {
1406  %s
1407              default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%%s" must be defined.', $name));
1408          }
1409          $this->loadedDynamicParameters[$name] = true;
1410   
1411          return $this->dynamicParameters[$name] = $value;
1412  EOF;
1413   
1414                  $getDynamicParameter = sprintf($getDynamicParameter, implode("\n", $dynamicPhp));
1415              } else {
1416                  $loadedDynamicParameters = '[]';
1417                  $getDynamicParameter = str_repeat(' ', 8).'throw new InvalidArgumentException(sprintf(\'The dynamic parameter "%s" must be defined.\', $name));';
1418              }
1419   
1420              $code .= <<<EOF
1421   
1422      private \$loadedDynamicParameters = {$loadedDynamicParameters};
1423      private \$dynamicParameters = [];
1424   
1425      /*{$this->docStar}
1426       * Computes a dynamic parameter.
1427       *
1428       * @param string \$name The name of the dynamic parameter to load
1429       *
1430       * @return mixed The value of the dynamic parameter
1431       *
1432       * @throws InvalidArgumentException When the dynamic parameter does not exist
1433       */
1434      private function getDynamicParameter(\$name)
1435      {
1436  {$getDynamicParameter}
1437      }
1438   
1439   
1440  EOF;
1441   
1442   
1443              $code .= '    private $normalizedParameterNames = '.($normalizedParams ? sprintf("[\n%s\n    ];", implode("\n", $normalizedParams)) : '[];')."\n";
1444              $code .= <<<'EOF'
1445   
1446      private function normalizeParameterName($name)
1447      {
1448          if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) {
1449              $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName;
1450              if ((string) $name !== $normalizedName) {
1451                  @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED);
1452              }
1453          } else {
1454              $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name;
1455          }
1456   
1457          return $normalizedName;
1458      }
1459   
1460  EOF;
1461   
1462          } elseif ($dynamicPhp) {
1463              throw new RuntimeException('You cannot dump a not-frozen container with dynamic parameters.');
1464          }
1465   
1466          $code .= <<<EOF
1467   
1468      /*{$this->docStar}
1469       * Gets the default parameters.
1470       *
1471       * @return array An array of the default parameters
1472       */
1473      protected function getDefaultParameters()
1474      {
1475          return $parameters;
1476      }
1477   
1478  EOF;
1479   
1480   
1481          return $code;
1482      }
1483   
1484      /**
1485       * Exports parameters.
1486       *
1487       * @param string $path
1488       * @param int    $indent
1489       *
1490       * @return string
1491       *
1492       * @throws InvalidArgumentException
1493       */
1494      private function exportParameters(array $parameters, $path = '', $indent = 12)
1495      {
1496          $php = [];
1497          foreach ($parameters as $key => $value) {
1498              if (\is_array($value)) {
1499                  $value = $this->exportParameters($value, $path.'/'.$key, $indent + 4);
1500              } elseif ($value instanceof ArgumentInterface) {
1501                  throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain special arguments. "%s" found in "%s".', \get_class($value), $path.'/'.$key));
1502              } elseif ($value instanceof Variable) {
1503                  throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".', $value, $path.'/'.$key));
1504              } elseif ($value instanceof Definition) {
1505                  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));
1506              } elseif ($value instanceof Reference) {
1507                  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));
1508              } elseif ($value instanceof Expression) {
1509                  throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain expressions. Expression "%s" found in "%s".', $value, $path.'/'.$key));
1510              } else {
1511                  $value = $this->export($value);
1512              }
1513   
1514              $php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), $this->export($key), $value);
1515          }
1516   
1517          return sprintf("[\n%s\n%s]", implode("\n", $php), str_repeat(' ', $indent - 4));
1518      }
1519   
1520      /**
1521       * Ends the class definition.
1522       *
1523       * @return string
1524       */
1525      private function endClass()
1526      {
1527          return <<<'EOF'
1528  }
1529   
1530  EOF;
1531   
1532      }
1533   
1534      /**
1535       * Wraps the service conditionals.
1536       *
1537       * @param string $value
1538       * @param string $code
1539       *
1540       * @return string
1541       */
1542      private function wrapServiceConditionals($value, $code)
1543      {
1544          if (!$condition = $this->getServiceConditionals($value)) {
1545              return $code;
1546          }
1547   
1548          // re-indent the wrapped code
1549          $code = implode("\n", array_map(function ($line) { return $line ? '    '.$line : $line; }, explode("\n", $code)));
1550   
1551          return sprintf("        if (%s) {\n%s        }\n", $condition, $code);
1552      }
1553   
1554      /**
1555       * Get the conditions to execute for conditional services.
1556       *
1557       * @param string $value
1558       *
1559       * @return string|null
1560       */
1561      private function getServiceConditionals($value)
1562      {
1563          $conditions = [];
1564          foreach (ContainerBuilder::getInitializedConditionals($value) as $service) {
1565              if (!$this->container->hasDefinition($service)) {
1566                  return 'false';
1567              }
1568              $conditions[] = sprintf('isset($this->services[%s])', $this->doExport($service));
1569          }
1570          foreach (ContainerBuilder::getServiceConditionals($value) as $service) {
1571              if ($this->container->hasDefinition($service) && !$this->container->getDefinition($service)->isPublic()) {
1572                  continue;
1573              }
1574   
1575              $conditions[] = sprintf('$this->has(%s)', $this->doExport($service));
1576          }
1577   
1578          if (!$conditions) {
1579              return '';
1580          }
1581   
1582          return implode(' && ', $conditions);
1583      }
1584   
1585      private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions = null, array &$calls = [], $byConstructor = null)
1586      {
1587          if (null === $definitions) {
1588              $definitions = new \SplObjectStorage();
1589          }
1590   
1591          foreach ($arguments as $argument) {
1592              if (\is_array($argument)) {
1593                  $this->getDefinitionsFromArguments($argument, $definitions, $calls, $byConstructor);
1594              } elseif ($argument instanceof Reference) {
1595                  $id = $this->container->normalizeId($argument);
1596   
1597                  while ($this->container->hasAlias($id)) {
1598                      $id = (string) $this->container->getAlias($id);
1599                  }
1600   
1601                  if (!isset($calls[$id])) {
1602                      $calls[$id] = [0, $argument->getInvalidBehavior(), $byConstructor];
1603                  } else {
1604                      $calls[$id][1] = min($calls[$id][1], $argument->getInvalidBehavior());
1605                  }
1606   
1607                  ++$calls[$id][0];
1608              } elseif (!$argument instanceof Definition) {
1609                  // no-op
1610              } elseif (isset($definitions[$argument])) {
1611                  $definitions[$argument] = 1 + $definitions[$argument];
1612              } else {
1613                  $definitions[$argument] = 1;
1614                  $arguments = [$argument->getArguments(), $argument->getFactory()];
1615                  $this->getDefinitionsFromArguments($arguments, $definitions, $calls, null === $byConstructor || $byConstructor);
1616                  $arguments = [$argument->getProperties(), $argument->getMethodCalls(), $argument->getConfigurator()];
1617                  $this->getDefinitionsFromArguments($arguments, $definitions, $calls, null !== $byConstructor && $byConstructor);
1618              }
1619          }
1620   
1621          return $definitions;
1622      }
1623   
1624      /**
1625       * Dumps values.
1626       *
1627       * @param mixed $value
1628       * @param bool  $interpolate
1629       *
1630       * @return string
1631       *
1632       * @throws RuntimeException
1633       */
1634      private function dumpValue($value, $interpolate = true)
1635      {
1636          if (\is_array($value)) {
1637              if ($value && $interpolate && false !== $param = array_search($value, $this->container->getParameterBag()->all(), true)) {
1638                  return $this->dumpValue("%$param%");
1639              }
1640              $code = [];
1641              foreach ($value as $k => $v) {
1642                  $code[] = sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
1643              }
1644   
1645              return sprintf('[%s]', implode(', ', $code));
1646          } elseif ($value instanceof ArgumentInterface) {
1647              $scope = [$this->definitionVariables, $this->referenceVariables];
1648              $this->definitionVariables = $this->referenceVariables = null;
1649   
1650              try {
1651                  if ($value instanceof ServiceClosureArgument) {
1652                      $value = $value->getValues()[0];
1653                      $code = $this->dumpValue($value, $interpolate);
1654   
1655                      if ($value instanceof TypedReference) {
1656                          $code = sprintf('$f = function (\\%s $v%s) { return $v; }; return $f(%s);', $value->getType(), ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $value->getInvalidBehavior() ? ' = null' : '', $code);
1657                      } else {
1658                          $code = sprintf('return %s;', $code);
1659                      }
1660   
1661                      return sprintf("function () {\n            %s\n        }", $code);
1662                  }
1663   
1664                  if ($value instanceof IteratorArgument) {
1665                      $operands = [0];
1666                      $code = [];
1667                      $code[] = 'new RewindableGenerator(function () {';
1668   
1669                      if (!$values = $value->getValues()) {
1670                          $code[] = '            return new \EmptyIterator();';
1671                      } else {
1672                          $countCode = [];
1673                          $countCode[] = 'function () {';
1674   
1675                          foreach ($values as $k => $v) {
1676                              ($c = $this->getServiceConditionals($v)) ? $operands[] = "(int) ($c)" : ++$operands[0];
1677                              $v = $this->wrapServiceConditionals($v, sprintf("        yield %s => %s;\n", $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate)));
1678                              foreach (explode("\n", $v) as $v) {
1679                                  if ($v) {
1680                                      $code[] = '    '.$v;
1681                                  }
1682                              }
1683                          }
1684   
1685                          $countCode[] = sprintf('            return %s;', implode(' + ', $operands));
1686                          $countCode[] = '        }';
1687                      }
1688   
1689                      $code[] = sprintf('        }, %s)', \count($operands) > 1 ? implode("\n", $countCode) : $operands[0]);
1690   
1691                      return implode("\n", $code);
1692                  }
1693              } finally {
1694                  list($this->definitionVariables, $this->referenceVariables) = $scope;
1695              }
1696          } elseif ($value instanceof Definition) {
1697              if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {
1698                  return $this->dumpValue($this->definitionVariables[$value], $interpolate);
1699              }
1700              if ($value->getMethodCalls()) {
1701                  throw new RuntimeException('Cannot dump definitions which have method calls.');
1702              }
1703              if ($value->getProperties()) {
1704                  throw new RuntimeException('Cannot dump definitions which have properties.');
1705              }
1706              if (null !== $value->getConfigurator()) {
1707                  throw new RuntimeException('Cannot dump definitions which have a configurator.');
1708              }
1709   
1710              $arguments = [];
1711              foreach ($value->getArguments() as $argument) {
1712                  $arguments[] = $this->dumpValue($argument);
1713              }
1714   
1715              if (null !== $value->getFactory()) {
1716                  $factory = $value->getFactory();
1717   
1718                  if (\is_string($factory)) {
1719                      return sprintf('%s(%s)', $this->dumpLiteralClass($this->dumpValue($factory)), implode(', ', $arguments));
1720                  }
1721   
1722                  if (\is_array($factory)) {
1723                      if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $factory[1])) {
1724                          throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s).', $factory[1] ?: 'n/a'));
1725                      }
1726   
1727                      $class = $this->dumpValue($factory[0]);
1728                      if (\is_string($factory[0])) {
1729                          return sprintf('%s::%s(%s)', $this->dumpLiteralClass($class), $factory[1], implode(', ', $arguments));
1730                      }
1731   
1732                      if ($factory[0] instanceof Definition) {
1733                          if (0 === strpos($class, 'new ')) {
1734                              return sprintf('(%s)->%s(%s)', $class, $factory[1], implode(', ', $arguments));
1735                          }
1736   
1737                          return sprintf("\\call_user_func([%s, '%s']%s)", $class, $factory[1], \count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1738                      }
1739   
1740                      if ($factory[0] instanceof Reference) {
1741                          return sprintf('%s->%s(%s)', $class, $factory[1], implode(', ', $arguments));
1742                      }
1743                  }
1744   
1745                  throw new RuntimeException('Cannot dump definition because of invalid factory.');
1746              }
1747   
1748              $class = $value->getClass();
1749              if (null === $class) {
1750                  throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
1751              }
1752   
1753              return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments));
1754          } elseif ($value instanceof Variable) {
1755              return '$'.$value;
1756          } elseif ($value instanceof Reference) {
1757              $id = $this->container->normalizeId($value);
1758   
1759              while ($this->container->hasAlias($id)) {
1760                  $id = (string) $this->container->getAlias($id);
1761              }
1762   
1763              if (null !== $this->referenceVariables && isset($this->referenceVariables[$id])) {
1764                  return $this->dumpValue($this->referenceVariables[$id], $interpolate);
1765              }
1766   
1767              return $this->getServiceCall($id, $value);
1768          } elseif ($value instanceof Expression) {
1769              return $this->getExpressionLanguage()->compile((string) $value, ['this' => 'container']);
1770          } elseif ($value instanceof Parameter) {
1771              return $this->dumpParameter($value);
1772          } elseif (true === $interpolate && \is_string($value)) {
1773              if (preg_match('/^%([^%]+)%$/', $value, $match)) {
1774                  // we do this to deal with non string values (Boolean, integer, ...)
1775                  // the preg_replace_callback converts them to strings
1776                  return $this->dumpParameter($match[1]);
1777              } else {
1778                  $replaceParameters = function ($match) {
1779                      return "'.".$this->dumpParameter($match[2]).".'";
1780                  };
1781   
1782                  $code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, $this->export($value)));
1783   
1784                  return $code;
1785              }
1786          } elseif (\is_object($value) || \is_resource($value)) {
1787              throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
1788          }
1789   
1790          return $this->export($value);
1791      }
1792   
1793      /**
1794       * Dumps a string to a literal (aka PHP Code) class value.
1795       *
1796       * @param string $class
1797       *
1798       * @return string
1799       *
1800       * @throws RuntimeException
1801       */
1802      private function dumpLiteralClass($class)
1803      {
1804          if (false !== strpos($class, '$')) {
1805              return sprintf('${($_ = %s) && false ?: "_"}', $class);
1806          }
1807          if (0 !== strpos($class, "'") || !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
1808              throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s).', $class ?: 'n/a'));
1809          }
1810   
1811          $class = substr(str_replace('\\\\', '\\', $class), 1, -1);
1812   
1813          return 0 === strpos($class, '\\') ? $class : '\\'.$class;
1814      }
1815   
1816      /**
1817       * Dumps a parameter.
1818       *
1819       * @param string $name
1820       *
1821       * @return string
1822       */
1823      private function dumpParameter($name)
1824      {
1825          $name = (string) $name;
1826   
1827          if ($this->container->isCompiled() && $this->container->hasParameter($name)) {
1828              $value = $this->container->getParameter($name);
1829              $dumpedValue = $this->dumpValue($value, false);
1830   
1831              if (!$value || !\is_array($value)) {
1832                  return $dumpedValue;
1833              }
1834   
1835              if (!preg_match("/\\\$this->(?:getEnv\('(?:\w++:)*+\w++'\)|targetDirs\[\d++\])/", $dumpedValue)) {
1836                  return sprintf('$this->parameters[%s]', $this->doExport($name));
1837              }
1838          }
1839   
1840          return sprintf('$this->getParameter(%s)', $this->doExport($name));
1841      }
1842   
1843      /**
1844       * Gets a service call.
1845       *
1846       * @param string    $id
1847       * @param Reference $reference
1848       *
1849       * @return string
1850       */
1851      private function getServiceCall($id, Reference $reference = null)
1852      {
1853          while ($this->container->hasAlias($id)) {
1854              $id = (string) $this->container->getAlias($id);
1855          }
1856          $id = $this->container->normalizeId($id);
1857   
1858          if ('service_container' === $id) {
1859              return '$this';
1860          }
1861   
1862          if ($this->container->hasDefinition($id) && $definition = $this->container->getDefinition($id)) {
1863              if ($definition->isSynthetic()) {
1864                  $code = sprintf('$this->get(%s%s)', $this->doExport($id), null !== $reference ? ', '.$reference->getInvalidBehavior() : '');
1865              } elseif (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) {
1866                  $code = 'null';
1867                  if (!$definition->isShared()) {
1868                      return $code;
1869                  }
1870              } elseif ($this->isTrivialInstance($definition)) {
1871                  $code = substr($this->addNewInstance($definition, '', '', $id), 8, -2);
1872                  if ($definition->isShared()) {
1873                      $code = sprintf('$this->services[%s] = %s', $this->doExport($id), $code);
1874                  }
1875                  $code = "($code)";
1876              } elseif ($this->asFiles && $definition->isShared() && !$this->isHotPath($definition)) {
1877                  $code = sprintf("\$this->load('%s.php')", $this->generateMethodName($id));
1878              } else {
1879                  $code = sprintf('$this->%s()', $this->generateMethodName($id));
1880              }
1881          } elseif (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) {
1882              return 'null';
1883          } elseif (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
1884              $code = sprintf('$this->get(%s, /* ContainerInterface::NULL_ON_INVALID_REFERENCE */ %d)', $this->doExport($id), ContainerInterface::NULL_ON_INVALID_REFERENCE);
1885          } else {
1886              $code = sprintf('$this->get(%s)', $this->doExport($id));
1887          }
1888   
1889          // The following is PHP 5.5 syntax for what could be written as "(\$this->services['$id'] ?? $code)" on PHP>=7.0
1890   
1891          return sprintf("\${(\$_ = isset(\$this->services[%s]) ? \$this->services[%1\$s] : %s) && false ?: '_'}", $this->doExport($id), $code);
1892      }
1893   
1894      /**
1895       * Initializes the method names map to avoid conflicts with the Container methods.
1896       *
1897       * @param string $class the container base class
1898       */
1899      private function initializeMethodNamesMap($class)
1900      {
1901          $this->serviceIdToMethodNameMap = [];
1902          $this->usedMethodNames = [];
1903   
1904          if ($reflectionClass = $this->container->getReflectionClass($class)) {
1905              foreach ($reflectionClass->getMethods() as $method) {
1906                  $this->usedMethodNames[strtolower($method->getName())] = true;
1907              }
1908          }
1909      }
1910   
1911      /**
1912       * Convert a service id to a valid PHP method name.
1913       *
1914       * @param string $id
1915       *
1916       * @return string
1917       *
1918       * @throws InvalidArgumentException
1919       */
1920      private function generateMethodName($id)
1921      {
1922          if (isset($this->serviceIdToMethodNameMap[$id])) {
1923              return $this->serviceIdToMethodNameMap[$id];
1924          }
1925   
1926          $i = strrpos($id, '\\');
1927          $name = Container::camelize(false !== $i && isset($id[1 + $i]) ? substr($id, 1 + $i) : $id);
1928          $name = preg_replace('/[^a-zA-Z0-9_\x7f-\xff]/', '', $name);
1929          $methodName = 'get'.$name.'Service';
1930          $suffix = 1;
1931   
1932          while (isset($this->usedMethodNames[strtolower($methodName)])) {
1933              ++$suffix;
1934              $methodName = 'get'.$name.$suffix.'Service';
1935          }
1936   
1937          $this->serviceIdToMethodNameMap[$id] = $methodName;
1938          $this->usedMethodNames[strtolower($methodName)] = true;
1939   
1940          return $methodName;
1941      }
1942   
1943      /**
1944       * Returns the next name to use.
1945       *
1946       * @return string
1947       */
1948      private function getNextVariableName()
1949      {
1950          $firstChars = self::FIRST_CHARS;
1951          $firstCharsLength = \strlen($firstChars);
1952          $nonFirstChars = self::NON_FIRST_CHARS;
1953          $nonFirstCharsLength = \strlen($nonFirstChars);
1954   
1955          while (true) {
1956              $name = '';
1957              $i = $this->variableCount;
1958   
1959              if ('' === $name) {
1960                  $name .= $firstChars[$i % $firstCharsLength];
1961                  $i = (int) ($i / $firstCharsLength);
1962              }
1963   
1964              while ($i > 0) {
1965                  --$i;
1966                  $name .= $nonFirstChars[$i % $nonFirstCharsLength];
1967                  $i = (int) ($i / $nonFirstCharsLength);
1968              }
1969   
1970              ++$this->variableCount;
1971   
1972              // check that the name is not reserved
1973              if (\in_array($name, $this->reservedVariables, true)) {
1974                  continue;
1975              }
1976   
1977              return $name;
1978          }
1979      }
1980   
1981      private function getExpressionLanguage()
1982      {
1983          if (null === $this->expressionLanguage) {
1984              if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
1985                  throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
1986              }
1987              $providers = $this->container->getExpressionLanguageProviders();
1988              $this->expressionLanguage = new ExpressionLanguage(null, $providers, function ($arg) {
1989                  $id = '""' === substr_replace($arg, '', 1, -1) ? stripcslashes(substr($arg, 1, -1)) : null;
1990   
1991                  if (null !== $id && ($this->container->hasAlias($id) || $this->container->hasDefinition($id))) {
1992                      return $this->getServiceCall($id);
1993                  }
1994   
1995                  return sprintf('$this->get(%s)', $arg);
1996              });
1997   
1998              if ($this->container->isTrackingResources()) {
1999                  foreach ($providers as $provider) {
2000                      $this->container->addObjectResource($provider);
2001                  }
2002              }
2003          }
2004   
2005          return $this->expressionLanguage;
2006      }
2007   
2008      private function isHotPath(Definition $definition)
2009      {
2010          return $this->hotPathTag && $definition->hasTag($this->hotPathTag) && !$definition->isDeprecated();
2011      }
2012   
2013      private function export($value)
2014      {
2015          if (null !== $this->targetDirRegex && \is_string($value) && preg_match($this->targetDirRegex, $value, $matches, \PREG_OFFSET_CAPTURE)) {
2016              $suffix = $matches[0][1] + \strlen($matches[0][0]);
2017              $matches[0][1] += \strlen($matches[1][0]);
2018              $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : '';
2019              $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : '';
2020              $dirname = $this->asFiles ? '$this->containerDir' : '__DIR__';
2021              $offset = 2 + $this->targetDirMaxMatches - \count($matches);
2022   
2023              if ($this->asFiles || 0 < $offset) {
2024                  $dirname = sprintf('$this->targetDirs[%d]', $offset);
2025              }
2026   
2027              if ($prefix || $suffix) {
2028                  return sprintf('(%s%s%s)', $prefix, $dirname, $suffix);
2029              }
2030   
2031              return $dirname;
2032          }
2033   
2034          return $this->doExport($value, true);
2035      }
2036   
2037      private function doExport($value, $resolveEnv = false)
2038      {
2039          if (\is_string($value) && false !== strpos($value, "\n")) {
2040              $cleanParts = explode("\n", $value);
2041              $cleanParts = array_map(function ($part) { return var_export($part, true); }, $cleanParts);
2042              $export = implode('."\n".', $cleanParts);
2043          } else {
2044              $export = var_export($value, true);
2045          }
2046   
2047          if ($resolveEnv && "'" === $export[0] && $export !== $resolvedExport = $this->container->resolveEnvPlaceholders($export, "'.\$this->getEnv('string:%s').'")) {
2048              $export = $resolvedExport;
2049              if (".''" === substr($export, -3)) {
2050                  $export = substr($export, 0, -3);
2051                  if ("'" === $export[1]) {
2052                      $export = substr_replace($export, '', 18, 7);
2053                  }
2054              }
2055              if ("'" === $export[1]) {
2056                  $export = substr($export, 3);
2057              }
2058          }
2059   
2060          return $export;
2061      }
2062  }
2063