vendor/symfony/dependency-injection/Dumper/PhpDumper.php line 559

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\DependencyInjection\Dumper;
  11. use Composer\Autoload\ClassLoader;
  12. use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader;
  13. use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
  14. use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
  15. use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
  16. use Symfony\Component\DependencyInjection\Argument\ServiceLocator;
  17. use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
  18. use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
  19. use Symfony\Component\DependencyInjection\Compiler\CheckCircularReferencesPass;
  20. use Symfony\Component\DependencyInjection\Compiler\ServiceReferenceGraphNode;
  21. use Symfony\Component\DependencyInjection\Container;
  22. use Symfony\Component\DependencyInjection\ContainerBuilder;
  23. use Symfony\Component\DependencyInjection\ContainerInterface;
  24. use Symfony\Component\DependencyInjection\Definition;
  25. use Symfony\Component\DependencyInjection\Exception\EnvParameterException;
  26. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  27. use Symfony\Component\DependencyInjection\Exception\LogicException;
  28. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  29. use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
  30. use Symfony\Component\DependencyInjection\ExpressionLanguage;
  31. use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
  32. use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
  33. use Symfony\Component\DependencyInjection\Loader\FileLoader;
  34. use Symfony\Component\DependencyInjection\Parameter;
  35. use Symfony\Component\DependencyInjection\Reference;
  36. use Symfony\Component\DependencyInjection\ServiceLocator as BaseServiceLocator;
  37. use Symfony\Component\DependencyInjection\TypedReference;
  38. use Symfony\Component\DependencyInjection\Variable;
  39. use Symfony\Component\ErrorHandler\DebugClassLoader;
  40. use Symfony\Component\ExpressionLanguage\Expression;
  41. use Symfony\Component\HttpKernel\Kernel;
  42. /**
  43.  * PhpDumper dumps a service container as a PHP class.
  44.  *
  45.  * @author Fabien Potencier <fabien@symfony.com>
  46.  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  47.  */
  48. class PhpDumper extends Dumper
  49. {
  50.     /**
  51.      * Characters that might appear in the generated variable name as first character.
  52.      */
  53.     const FIRST_CHARS 'abcdefghijklmnopqrstuvwxyz';
  54.     /**
  55.      * Characters that might appear in the generated variable name as any but the first character.
  56.      */
  57.     const NON_FIRST_CHARS 'abcdefghijklmnopqrstuvwxyz0123456789_';
  58.     private $definitionVariables;
  59.     private $referenceVariables;
  60.     private $variableCount;
  61.     private $inlinedDefinitions;
  62.     private $serviceCalls;
  63.     private $reservedVariables = ['instance''class''this'];
  64.     private $expressionLanguage;
  65.     private $targetDirRegex;
  66.     private $targetDirMaxMatches;
  67.     private $docStar;
  68.     private $serviceIdToMethodNameMap;
  69.     private $usedMethodNames;
  70.     private $namespace;
  71.     private $asFiles;
  72.     private $hotPathTag;
  73.     private $inlineFactories;
  74.     private $inlineRequires;
  75.     private $inlinedRequires = [];
  76.     private $circularReferences = [];
  77.     private $singleUsePrivateIds = [];
  78.     private $preload = [];
  79.     private $addThrow false;
  80.     private $addGetService false;
  81.     private $locatedIds = [];
  82.     private $serviceLocatorTag;
  83.     private $exportedVariables = [];
  84.     private $baseClass;
  85.     /**
  86.      * @var ProxyDumper
  87.      */
  88.     private $proxyDumper;
  89.     /**
  90.      * {@inheritdoc}
  91.      */
  92.     public function __construct(ContainerBuilder $container)
  93.     {
  94.         if (!$container->isCompiled()) {
  95.             throw new LogicException('Cannot dump an uncompiled container.');
  96.         }
  97.         parent::__construct($container);
  98.     }
  99.     /**
  100.      * Sets the dumper to be used when dumping proxies in the generated container.
  101.      */
  102.     public function setProxyDumper(ProxyDumper $proxyDumper)
  103.     {
  104.         $this->proxyDumper $proxyDumper;
  105.     }
  106.     /**
  107.      * Dumps the service container as a PHP class.
  108.      *
  109.      * Available options:
  110.      *
  111.      *  * class:      The class name
  112.      *  * base_class: The base class name
  113.      *  * namespace:  The class namespace
  114.      *  * as_files:   To split the container in several files
  115.      *
  116.      * @return string|array A PHP class representing the service container or an array of PHP files if the "as_files" option is set
  117.      *
  118.      * @throws EnvParameterException When an env var exists but has not been dumped
  119.      */
  120.     public function dump(array $options = [])
  121.     {
  122.         $this->locatedIds = [];
  123.         $this->targetDirRegex null;
  124.         $this->inlinedRequires = [];
  125.         $this->exportedVariables = [];
  126.         $options array_merge([
  127.             'class' => 'ProjectServiceContainer',
  128.             'base_class' => 'Container',
  129.             'namespace' => '',
  130.             'as_files' => false,
  131.             'debug' => true,
  132.             'hot_path_tag' => 'container.hot_path',
  133.             'inline_factories_parameter' => 'container.dumper.inline_factories',
  134.             'inline_class_loader_parameter' => 'container.dumper.inline_class_loader',
  135.             'preload_classes' => [],
  136.             'service_locator_tag' => 'container.service_locator',
  137.             'build_time' => time(),
  138.         ], $options);
  139.         $this->addThrow $this->addGetService false;
  140.         $this->namespace $options['namespace'];
  141.         $this->asFiles $options['as_files'];
  142.         $this->hotPathTag $options['hot_path_tag'];
  143.         $this->inlineFactories $this->asFiles && $options['inline_factories_parameter'] && $this->container->hasParameter($options['inline_factories_parameter']) && $this->container->getParameter($options['inline_factories_parameter']);
  144.         $this->inlineRequires $options['inline_class_loader_parameter'] && $this->container->hasParameter($options['inline_class_loader_parameter']) && $this->container->getParameter($options['inline_class_loader_parameter']);
  145.         $this->serviceLocatorTag $options['service_locator_tag'];
  146.         if (!== strpos($baseClass $options['base_class'], '\\') && 'Container' !== $baseClass) {
  147.             $baseClass sprintf('%s\%s'$options['namespace'] ? '\\'.$options['namespace'] : ''$baseClass);
  148.             $this->baseClass $baseClass;
  149.         } elseif ('Container' === $baseClass) {
  150.             $this->baseClass Container::class;
  151.         } else {
  152.             $this->baseClass $baseClass;
  153.         }
  154.         $this->initializeMethodNamesMap('Container' === $baseClass Container::class : $baseClass);
  155.         if ($this->getProxyDumper() instanceof NullDumper) {
  156.             (new AnalyzeServiceReferencesPass(truefalse))->process($this->container);
  157.             try {
  158.                 (new CheckCircularReferencesPass())->process($this->container);
  159.             } catch (ServiceCircularReferenceException $e) {
  160.                 $path $e->getPath();
  161.                 end($path);
  162.                 $path[key($path)] .= '". Try running "composer require symfony/proxy-manager-bridge';
  163.                 throw new ServiceCircularReferenceException($e->getServiceId(), $path);
  164.             }
  165.         }
  166.         (new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
  167.         $checkedNodes = [];
  168.         $this->circularReferences = [];
  169.         $this->singleUsePrivateIds = [];
  170.         foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
  171.             if (!$node->getValue() instanceof Definition) {
  172.                 continue;
  173.             }
  174.             if (!isset($checkedNodes[$id])) {
  175.                 $this->analyzeCircularReferences($id$node->getOutEdges(), $checkedNodes);
  176.             }
  177.             if ($this->isSingleUsePrivateNode($node)) {
  178.                 $this->singleUsePrivateIds[$id] = $id;
  179.             }
  180.         }
  181.         $this->container->getCompiler()->getServiceReferenceGraph()->clear();
  182.         $checkedNodes = [];
  183.         $this->singleUsePrivateIds array_diff_key($this->singleUsePrivateIds$this->circularReferences);
  184.         $this->docStar $options['debug'] ? '*' '';
  185.         if (!empty($options['file']) && is_dir($dir = \dirname($options['file']))) {
  186.             // Build a regexp where the first root dirs are mandatory,
  187.             // but every other sub-dir is optional up to the full path in $dir
  188.             // Mandate at least 1 root dir and not more than 5 optional dirs.
  189.             $dir explode(\DIRECTORY_SEPARATORrealpath($dir));
  190.             $i = \count($dir);
  191.             if (+ (int) ('\\' === \DIRECTORY_SEPARATOR) <= $i) {
  192.                 $regex '';
  193.                 $lastOptionalDir $i $i : (+ (int) ('\\' === \DIRECTORY_SEPARATOR));
  194.                 $this->targetDirMaxMatches $i $lastOptionalDir;
  195.                 while (--$i >= $lastOptionalDir) {
  196.                     $regex sprintf('(%s%s)?'preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#'), $regex);
  197.                 }
  198.                 do {
  199.                     $regex preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#').$regex;
  200.                 } while (< --$i);
  201.                 $this->targetDirRegex '#'.preg_quote($dir[0], '#').$regex.'#';
  202.             }
  203.         }
  204.         $proxyClasses $this->inlineFactories $this->generateProxyClasses() : null;
  205.         if ($options['preload_classes']) {
  206.             $this->preload array_combine($options['preload_classes'], $options['preload_classes']);
  207.         }
  208.         $code =
  209.             $this->startClass($options['class'], $baseClass).
  210.             $this->addServices($services).
  211.             $this->addDeprecatedAliases().
  212.             $this->addDefaultParametersMethod()
  213.         ;
  214.         $proxyClasses $proxyClasses ?? $this->generateProxyClasses();
  215.         if ($this->addGetService) {
  216.             $code preg_replace(
  217.                 "/(\r?\n\r?\n    public function __construct.+?\\{\r?\n)/s",
  218.                 "\n    private \$getService;$1        \$this->getService = \\Closure::fromCallable([\$this, 'getService']);\n",
  219.                 $code,
  220.                 1
  221.             );
  222.         }
  223.         if ($this->asFiles) {
  224.             $fileStart = <<<EOF
  225. <?php
  226. use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
  227. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  228. // This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
  229. EOF;
  230.             $files = [];
  231.             $ids $this->container->getRemovedIds();
  232.             foreach ($this->container->getDefinitions() as $id => $definition) {
  233.                 if (!$definition->isPublic()) {
  234.                     $ids[$id] = true;
  235.                 }
  236.             }
  237.             if ($ids array_keys($ids)) {
  238.                 sort($ids);
  239.                 $c "<?php\n\nreturn [\n";
  240.                 foreach ($ids as $id) {
  241.                     $c .= '    '.$this->doExport($id)." => true,\n";
  242.                 }
  243.                 $files['removed-ids.php'] = $c."];\n";
  244.             }
  245.             if (!$this->inlineFactories) {
  246.                 foreach ($this->generateServiceFiles($services) as $file => $c) {
  247.                     $files[$file] = $fileStart.$c;
  248.                 }
  249.                 foreach ($proxyClasses as $file => $c) {
  250.                     $files[$file] = "<?php\n".$c;
  251.                 }
  252.             }
  253.             $code .= $this->endClass();
  254.             if ($this->inlineFactories) {
  255.                 foreach ($proxyClasses as $c) {
  256.                     $code .= $c;
  257.                 }
  258.             }
  259.             $files[$options['class'].'.php'] = $code;
  260.             $hash ucfirst(strtr(ContainerBuilder::hash($files), '._''xx'));
  261.             $code = [];
  262.             foreach ($files as $file => $c) {
  263.                 $code["Container{$hash}/{$file}"] = $c;
  264.             }
  265.             array_pop($code);
  266.             $code["Container{$hash}/{$options['class']}.php"] = substr_replace($files[$options['class'].'.php'], "<?php\n\nnamespace Container{$hash};\n"06);
  267.             $namespaceLine $this->namespace "\nnamespace {$this->namespace};\n" '';
  268.             $time $options['build_time'];
  269.             $id hash('crc32'$hash.$time);
  270.             $this->asFiles false;
  271.             if ($this->preload && null !== $autoloadFile $this->getAutoloadFile()) {
  272.                 $autoloadFile substr($this->export($autoloadFile), 2, -1);
  273.                 $code[$options['class'].'.preload.php'] = <<<EOF
  274. <?php
  275. // This file has been auto-generated by the Symfony Dependency Injection Component
  276. // You can reference it in the "opcache.preload" php.ini setting on PHP >= 7.4 when preloading is desired
  277. use Symfony\Component\DependencyInjection\Dumper\Preloader;
  278. require $autoloadFile;
  279. require __DIR__.'/Container{$hash}/{$options['class']}.php';
  280. \$classes = [];
  281. EOF;
  282.                 foreach ($this->preload as $class) {
  283.                     if (!$class || false !== strpos($class'$')) {
  284.                         continue;
  285.                     }
  286.                     if (!(class_exists($classfalse) || interface_exists($classfalse) || trait_exists($classfalse)) || (new \ReflectionClass($class))->isUserDefined()) {
  287.                         $code[$options['class'].'.preload.php'] .= sprintf("\$classes[] = '%s';\n"$class);
  288.                     }
  289.                 }
  290.                 $code[$options['class'].'.preload.php'] .= <<<'EOF'
  291. Preloader::preload($classes);
  292. EOF;
  293.             }
  294.             $code[$options['class'].'.php'] = <<<EOF
  295. <?php
  296. {$namespaceLine}
  297. // This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
  298. if (\\class_exists(\\Container{$hash}\\{$options['class']}::class, false)) {
  299.     // no-op
  300. } elseif (!include __DIR__.'/Container{$hash}/{$options['class']}.php') {
  301.     touch(__DIR__.'/Container{$hash}.legacy');
  302.     return;
  303. }
  304. if (!\\class_exists({$options['class']}::class, false)) {
  305.     \\class_alias(\\Container{$hash}\\{$options['class']}::class, {$options['class']}::class, false);
  306. }
  307. return new \\Container{$hash}\\{$options['class']}([
  308.     'container.build_hash' => '$hash',
  309.     'container.build_id' => '$id',
  310.     'container.build_time' => $time,
  311. ], __DIR__.\\DIRECTORY_SEPARATOR.'Container{$hash}');
  312. EOF;
  313.         } else {
  314.             $code .= $this->endClass();
  315.             foreach ($proxyClasses as $c) {
  316.                 $code .= $c;
  317.             }
  318.         }
  319.         $this->targetDirRegex null;
  320.         $this->inlinedRequires = [];
  321.         $this->circularReferences = [];
  322.         $this->locatedIds = [];
  323.         $this->exportedVariables = [];
  324.         $this->preload = [];
  325.         $unusedEnvs = [];
  326.         foreach ($this->container->getEnvCounters() as $env => $use) {
  327.             if (!$use) {
  328.                 $unusedEnvs[] = $env;
  329.             }
  330.         }
  331.         if ($unusedEnvs) {
  332.             throw new EnvParameterException($unusedEnvsnull'Environment variables "%s" are never used. Please, check your container\'s configuration.');
  333.         }
  334.         return $code;
  335.     }
  336.     /**
  337.      * Retrieves the currently set proxy dumper or instantiates one.
  338.      */
  339.     private function getProxyDumper(): ProxyDumper
  340.     {
  341.         if (!$this->proxyDumper) {
  342.             $this->proxyDumper = new NullDumper();
  343.         }
  344.         return $this->proxyDumper;
  345.     }
  346.     private function analyzeCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array &$currentPath = [], bool $byConstructor true)
  347.     {
  348.         $checkedNodes[$sourceId] = true;
  349.         $currentPath[$sourceId] = $byConstructor;
  350.         foreach ($edges as $edge) {
  351.             $node $edge->getDestNode();
  352.             $id $node->getId();
  353.             if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isLazy() || $edge->isWeak()) {
  354.                 // no-op
  355.             } elseif (isset($currentPath[$id])) {
  356.                 $this->addCircularReferences($id$currentPath$edge->isReferencedByConstructor());
  357.             } elseif (!isset($checkedNodes[$id])) {
  358.                 $this->analyzeCircularReferences($id$node->getOutEdges(), $checkedNodes$currentPath$edge->isReferencedByConstructor());
  359.             } elseif (isset($this->circularReferences[$id])) {
  360.                 $this->connectCircularReferences($id$currentPath$edge->isReferencedByConstructor());
  361.             }
  362.         }
  363.         unset($currentPath[$sourceId]);
  364.     }
  365.     private function connectCircularReferences(string $sourceId, array &$currentPathbool $byConstructor, array &$subPath = [])
  366.     {
  367.         $currentPath[$sourceId] = $subPath[$sourceId] = $byConstructor;
  368.         foreach ($this->circularReferences[$sourceId] as $id => $byConstructor) {
  369.             if (isset($currentPath[$id])) {
  370.                 $this->addCircularReferences($id$currentPath$byConstructor);
  371.             } elseif (!isset($subPath[$id]) && isset($this->circularReferences[$id])) {
  372.                 $this->connectCircularReferences($id$currentPath$byConstructor$subPath);
  373.             }
  374.         }
  375.         unset($currentPath[$sourceId], $subPath[$sourceId]);
  376.     }
  377.     private function addCircularReferences(string $id, array $currentPathbool $byConstructor)
  378.     {
  379.         $currentPath[$id] = $byConstructor;
  380.         $circularRefs = [];
  381.         foreach (array_reverse($currentPath) as $parentId => $v) {
  382.             $byConstructor $byConstructor && $v;
  383.             $circularRefs[] = $parentId;
  384.             if ($parentId === $id) {
  385.                 break;
  386.             }
  387.         }
  388.         $currentId $id;
  389.         foreach ($circularRefs as $parentId) {
  390.             if (empty($this->circularReferences[$parentId][$currentId])) {
  391.                 $this->circularReferences[$parentId][$currentId] = $byConstructor;
  392.             }
  393.             $currentId $parentId;
  394.         }
  395.     }
  396.     private function collectLineage(string $class, array &$lineage)
  397.     {
  398.         if (isset($lineage[$class])) {
  399.             return;
  400.         }
  401.         if (!$r $this->container->getReflectionClass($classfalse)) {
  402.             return;
  403.         }
  404.         if (is_a($class$this->baseClasstrue)) {
  405.             return;
  406.         }
  407.         $file $r->getFileName();
  408.         if (!$file || $this->doExport($file) === $exportedFile $this->export($file)) {
  409.             return;
  410.         }
  411.         $lineage[$class] = substr($exportedFile1, -1);
  412.         if ($parent $r->getParentClass()) {
  413.             $this->collectLineage($parent->name$lineage);
  414.         }
  415.         foreach ($r->getInterfaces() as $parent) {
  416.             $this->collectLineage($parent->name$lineage);
  417.         }
  418.         foreach ($r->getTraits() as $parent) {
  419.             $this->collectLineage($parent->name$lineage);
  420.         }
  421.         unset($lineage[$class]);
  422.         $lineage[$class] = substr($exportedFile1, -1);
  423.     }
  424.     private function generateProxyClasses(): array
  425.     {
  426.         $proxyClasses = [];
  427.         $alreadyGenerated = [];
  428.         $definitions $this->container->getDefinitions();
  429.         $strip '' === $this->docStar && method_exists('Symfony\Component\HttpKernel\Kernel''stripComments');
  430.         $proxyDumper $this->getProxyDumper();
  431.         ksort($definitions);
  432.         foreach ($definitions as $definition) {
  433.             if (!$proxyDumper->isProxyCandidate($definition)) {
  434.                 continue;
  435.             }
  436.             if (isset($alreadyGenerated[$class $definition->getClass()])) {
  437.                 continue;
  438.             }
  439.             $alreadyGenerated[$class] = true;
  440.             // register class' reflector for resource tracking
  441.             $this->container->getReflectionClass($class);
  442.             if ("\n" === $proxyCode "\n".$proxyDumper->getProxyCode($definition)) {
  443.                 continue;
  444.             }
  445.             if ($this->inlineRequires) {
  446.                 $lineage = [];
  447.                 $this->collectLineage($class$lineage);
  448.                 $code '';
  449.                 foreach (array_diff_key(array_flip($lineage), $this->inlinedRequires) as $file => $class) {
  450.                     if ($this->inlineFactories) {
  451.                         $this->inlinedRequires[$file] = true;
  452.                     }
  453.                     $code .= sprintf("include_once %s;\n"$file);
  454.                 }
  455.                 $proxyCode $code.$proxyCode;
  456.             }
  457.             if ($strip) {
  458.                 $proxyCode "<?php\n".$proxyCode;
  459.                 $proxyCode substr(Kernel::stripComments($proxyCode), 5);
  460.             }
  461.             $proxyClasses[sprintf('%s.php'explode(' '$this->inlineRequires substr($proxyCode, \strlen($code)) : $proxyCode3)[1])] = $proxyCode;
  462.         }
  463.         return $proxyClasses;
  464.     }
  465.     private function addServiceInclude(string $cIdDefinition $definition): string
  466.     {
  467.         $code '';
  468.         if ($this->inlineRequires && (!$this->isHotPath($definition) || $this->getProxyDumper()->isProxyCandidate($definition))) {
  469.             $lineage = [];
  470.             foreach ($this->inlinedDefinitions as $def) {
  471.                 if (!$def->isDeprecated()) {
  472.                     foreach ($this->getClasses($def) as $class) {
  473.                         $this->collectLineage($class$lineage);
  474.                     }
  475.                 }
  476.             }
  477.             foreach ($this->serviceCalls as $id => list($callCount$behavior)) {
  478.                 if ('service_container' !== $id && $id !== $cId
  479.                     && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior
  480.                     && $this->container->has($id)
  481.                     && $this->isTrivialInstance($def $this->container->findDefinition($id))
  482.                 ) {
  483.                     foreach ($this->getClasses($def) as $class) {
  484.                         $this->collectLineage($class$lineage);
  485.                     }
  486.                 }
  487.             }
  488.             foreach (array_diff_key(array_flip($lineage), $this->inlinedRequires) as $file => $class) {
  489.                 $code .= sprintf("        include_once %s;\n"$file);
  490.             }
  491.         }
  492.         foreach ($this->inlinedDefinitions as $def) {
  493.             if ($file $def->getFile()) {
  494.                 $file $this->dumpValue($file);
  495.                 $file '(' === $file[0] ? substr($file1, -1) : $file;
  496.                 $code .= sprintf("        include_once %s;\n"$file);
  497.             }
  498.         }
  499.         if ('' !== $code) {
  500.             $code .= "\n";
  501.         }
  502.         return $code;
  503.     }
  504.     /**
  505.      * @throws InvalidArgumentException
  506.      * @throws RuntimeException
  507.      */
  508.     private function addServiceInstance(string $idDefinition $definitionbool $isSimpleInstance): string
  509.     {
  510.         $class $this->dumpValue($definition->getClass());
  511.         if (=== 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)) {
  512.             throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.'$class$id));
  513.         }
  514.         $isProxyCandidate $this->getProxyDumper()->isProxyCandidate($definition);
  515.         $instantiation '';
  516.         $lastWitherIndex null;
  517.         foreach ($definition->getMethodCalls() as $k => $call) {
  518.             if ($call[2] ?? false) {
  519.                 $lastWitherIndex $k;
  520.             }
  521.         }
  522.         if (!$isProxyCandidate && $definition->isShared() && !isset($this->singleUsePrivateIds[$id]) && null === $lastWitherIndex) {
  523.             $instantiation sprintf('$this->%s[%s] = %s'$this->container->getDefinition($id)->isPublic() ? 'services' 'privates'$this->doExport($id), $isSimpleInstance '' '$instance');
  524.         } elseif (!$isSimpleInstance) {
  525.             $instantiation '$instance';
  526.         }
  527.         $return '';
  528.         if ($isSimpleInstance) {
  529.             $return 'return ';
  530.         } else {
  531.             $instantiation .= ' = ';
  532.         }
  533.         return $this->addNewInstance($definition'        '.$return.$instantiation$id);
  534.     }
  535.     private function isTrivialInstance(Definition $definition): bool
  536.     {
  537.         if ($definition->hasErrors()) {
  538.             return true;
  539.         }
  540.         if ($definition->isSynthetic() || $definition->getFile() || $definition->getMethodCalls() || $definition->getProperties() || $definition->getConfigurator()) {
  541.             return false;
  542.         }
  543.         if ($definition->isDeprecated() || $definition->isLazy() || $definition->getFactory() || < \count($definition->getArguments())) {
  544.             return false;
  545.         }
  546.         foreach ($definition->getArguments() as $arg) {
  547.             if (!$arg || $arg instanceof Parameter) {
  548.                 continue;
  549.             }
  550.             if (\is_array($arg) && >= \count($arg)) {
  551.                 foreach ($arg as $k => $v) {
  552.                     if ($this->dumpValue($k) !== $this->dumpValue($kfalse)) {
  553.                         return false;
  554.                     }
  555.                     if (!$v || $v instanceof Parameter) {
  556.                         continue;
  557.                     }
  558.                     if ($v instanceof Reference && $this->container->has($id = (string) $v) && $this->container->findDefinition($id)->isSynthetic()) {
  559.                         continue;
  560.                     }
  561.                     if (!is_scalar($v) || $this->dumpValue($v) !== $this->dumpValue($vfalse)) {
  562.                         return false;
  563.                     }
  564.                 }
  565.             } elseif ($arg instanceof Reference && $this->container->has($id = (string) $arg) && $this->container->findDefinition($id)->isSynthetic()) {
  566.                 continue;
  567.             } elseif (!is_scalar($arg) || $this->dumpValue($arg) !== $this->dumpValue($argfalse)) {
  568.                 return false;
  569.             }
  570.         }
  571.         return true;
  572.     }
  573.     private function addServiceMethodCalls(Definition $definitionstring $variableName, ?string $sharedNonLazyId): string
  574.     {
  575.         $lastWitherIndex null;
  576.         foreach ($definition->getMethodCalls() as $k => $call) {
  577.             if ($call[2] ?? false) {
  578.                 $lastWitherIndex $k;
  579.             }
  580.         }
  581.         $calls '';
  582.         foreach ($definition->getMethodCalls() as $k => $call) {
  583.             $arguments = [];
  584.             foreach ($call[1] as $value) {
  585.                 $arguments[] = $this->dumpValue($value);
  586.             }
  587.             $witherAssignation '';
  588.             if ($call[2] ?? false) {
  589.                 if (null !== $sharedNonLazyId && $lastWitherIndex === $k) {
  590.                     $witherAssignation sprintf('$this->%s[\'%s\'] = '$definition->isPublic() ? 'services' 'privates'$sharedNonLazyId);
  591.                 }
  592.                 $witherAssignation .= sprintf('$%s = '$variableName);
  593.             }
  594.             $calls .= $this->wrapServiceConditionals($call[1], sprintf("        %s\$%s->%s(%s);\n"$witherAssignation$variableName$call[0], implode(', '$arguments)));
  595.         }
  596.         return $calls;
  597.     }
  598.     private function addServiceProperties(Definition $definitionstring $variableName 'instance'): string
  599.     {
  600.         $code '';
  601.         foreach ($definition->getProperties() as $name => $value) {
  602.             $code .= sprintf("        \$%s->%s = %s;\n"$variableName$name$this->dumpValue($value));
  603.         }
  604.         return $code;
  605.     }
  606.     private function addServiceConfigurator(Definition $definitionstring $variableName 'instance'): string
  607.     {
  608.         if (!$callable $definition->getConfigurator()) {
  609.             return '';
  610.         }
  611.         if (\is_array($callable)) {
  612.             if ($callable[0] instanceof Reference
  613.                 || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))
  614.             ) {
  615.                 return sprintf("        %s->%s(\$%s);\n"$this->dumpValue($callable[0]), $callable[1], $variableName);
  616.             }
  617.             $class $this->dumpValue($callable[0]);
  618.             // If the class is a string we can optimize away
  619.             if (=== strpos($class"'") && false === strpos($class'$')) {
  620.                 return sprintf("        %s::%s(\$%s);\n"$this->dumpLiteralClass($class), $callable[1], $variableName);
  621.             }
  622.             if (=== strpos($class'new ')) {
  623.                 return sprintf("        (%s)->%s(\$%s);\n"$this->dumpValue($callable[0]), $callable[1], $variableName);
  624.             }
  625.             return sprintf("        [%s, '%s'](\$%s);\n"$this->dumpValue($callable[0]), $callable[1], $variableName);
  626.         }
  627.         return sprintf("        %s(\$%s);\n"$callable$variableName);
  628.     }
  629.     private function addService(string $idDefinition $definition): array
  630.     {
  631.         $this->definitionVariables = new \SplObjectStorage();
  632.         $this->referenceVariables = [];
  633.         $this->variableCount 0;
  634.         $this->referenceVariables[$id] = new Variable('instance');
  635.         $return = [];
  636.         if ($class $definition->getClass()) {
  637.             $class $class instanceof Parameter '%'.$class.'%' $this->container->resolveEnvPlaceholders($class);
  638.             $return[] = sprintf(=== strpos($class'%') ? '@return object A %1$s instance' '@return \%s'ltrim($class'\\'));
  639.         } elseif ($definition->getFactory()) {
  640.             $factory $definition->getFactory();
  641.             if (\is_string($factory)) {
  642.                 $return[] = sprintf('@return object An instance returned by %s()'$factory);
  643.             } elseif (\is_array($factory) && (\is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) {
  644.                 $class $factory[0] instanceof Definition $factory[0]->getClass() : (string) $factory[0];
  645.                 $class $class instanceof Parameter '%'.$class.'%' $this->container->resolveEnvPlaceholders($class);
  646.                 $return[] = sprintf('@return object An instance returned by %s::%s()'$class$factory[1]);
  647.             }
  648.         }
  649.         if ($definition->isDeprecated()) {
  650.             if ($return && === strpos($return[\count($return) - 1], '@return')) {
  651.                 $return[] = '';
  652.             }
  653.             $return[] = sprintf('@deprecated %s'$definition->getDeprecationMessage($id));
  654.         }
  655.         $return str_replace("\n     * \n""\n     *\n"implode("\n     * "$return));
  656.         $return $this->container->resolveEnvPlaceholders($return);
  657.         $shared $definition->isShared() ? ' shared' '';
  658.         $public $definition->isPublic() ? 'public' 'private';
  659.         $autowired $definition->isAutowired() ? ' autowired' '';
  660.         if ($definition->isLazy()) {
  661.             $lazyInitialization '$lazyLoad = true';
  662.         } else {
  663.             $lazyInitialization '';
  664.         }
  665.         $asFile $this->asFiles && !$this->inlineFactories && !$this->isHotPath($definition);
  666.         $methodName $this->generateMethodName($id);
  667.         if ($asFile) {
  668.             $file $methodName.'.php';
  669.             $code "        // Returns the $public '$id'$shared$autowired service.\n\n";
  670.         } else {
  671.             $file null;
  672.             $code = <<<EOF
  673.     /*{$this->docStar}
  674.      * Gets the $public '$id'$shared$autowired service.
  675.      *
  676.      * $return
  677. EOF;
  678.             $code str_replace('*/'' '$code).<<<EOF
  679.      */
  680.     protected function {$methodName}($lazyInitialization)
  681.     {
  682. EOF;
  683.         }
  684.         if ($definition->hasErrors() && $e $definition->getErrors()) {
  685.             $this->addThrow true;
  686.             $code .= sprintf("        \$this->throw(%s);\n"$this->export(reset($e)));
  687.         } else {
  688.             $this->serviceCalls = [];
  689.             $this->inlinedDefinitions $this->getDefinitionsFromArguments([$definition], null$this->serviceCalls);
  690.             if ($definition->isDeprecated()) {
  691.                 $code .= sprintf("        @trigger_error(%s, E_USER_DEPRECATED);\n\n"$this->export($definition->getDeprecationMessage($id)));
  692.             } else {
  693.                 foreach ($this->inlinedDefinitions as $def) {
  694.                     foreach ($this->getClasses($def) as $class) {
  695.                         $this->preload[$class] = $class;
  696.                     }
  697.                 }
  698.             }
  699.             if ($this->getProxyDumper()->isProxyCandidate($definition)) {
  700.                 $factoryCode $asFile ? ($definition->isShared() ? "\$this->load('%s.php', false)" '$this->factories[%2$s](false)') : '$this->%s(false)';
  701.                 $code .= $this->getProxyDumper()->getProxyFactoryCode($definition$idsprintf($factoryCode$methodName$this->doExport($id)));
  702.             }
  703.             $code .= $this->addServiceInclude($id$definition);
  704.             $code .= $this->addInlineService($id$definition);
  705.         }
  706.         if ($asFile) {
  707.             $code implode("\n"array_map(function ($line) { return $line substr($line8) : $line; }, explode("\n"$code)));
  708.         } else {
  709.             $code .= "    }\n";
  710.         }
  711.         $this->definitionVariables $this->inlinedDefinitions null;
  712.         $this->referenceVariables $this->serviceCalls null;
  713.         return [$file$code];
  714.     }
  715.     private function addInlineVariables(string $idDefinition $definition, array $argumentsbool $forConstructor): string
  716.     {
  717.         $code '';
  718.         foreach ($arguments as $argument) {
  719.             if (\is_array($argument)) {
  720.                 $code .= $this->addInlineVariables($id$definition$argument$forConstructor);
  721.             } elseif ($argument instanceof Reference) {
  722.                 $code .= $this->addInlineReference($id$definition$argument$forConstructor);
  723.             } elseif ($argument instanceof Definition) {
  724.                 $code .= $this->addInlineService($id$definition$argument$forConstructor);
  725.             }
  726.         }
  727.         return $code;
  728.     }
  729.     private function addInlineReference(string $idDefinition $definitionstring $targetIdbool $forConstructor): string
  730.     {
  731.         while ($this->container->hasAlias($targetId)) {
  732.             $targetId = (string) $this->container->getAlias($targetId);
  733.         }
  734.         list($callCount$behavior) = $this->serviceCalls[$targetId];
  735.         if ($id === $targetId) {
  736.             return $this->addInlineService($id$definition$definition);
  737.         }
  738.         if ('service_container' === $targetId || isset($this->referenceVariables[$targetId])) {
  739.             return '';
  740.         }
  741.         $hasSelfRef = isset($this->circularReferences[$id][$targetId]) && !isset($this->definitionVariables[$definition]);
  742.         if ($hasSelfRef && !$forConstructor && !$forConstructor = !$this->circularReferences[$id][$targetId]) {
  743.             $code $this->addInlineService($id$definition$definition);
  744.         } else {
  745.             $code '';
  746.         }
  747.         if (isset($this->referenceVariables[$targetId]) || ($callCount && (!$hasSelfRef || !$forConstructor))) {
  748.             return $code;
  749.         }
  750.         $name $this->getNextVariableName();
  751.         $this->referenceVariables[$targetId] = new Variable($name);
  752.         $reference ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $behavior ? new Reference($targetId$behavior) : null;
  753.         $code .= sprintf("        \$%s = %s;\n"$name$this->getServiceCall($targetId$reference));
  754.         if (!$hasSelfRef || !$forConstructor) {
  755.             return $code;
  756.         }
  757.         $code .= sprintf(<<<'EOTXT'
  758.         if (isset($this->%s[%s])) {
  759.             return $this->%1$s[%2$s];
  760.         }
  761. EOTXT
  762.             ,
  763.             $this->container->getDefinition($id)->isPublic() ? 'services' 'privates',
  764.             $this->doExport($id)
  765.         );
  766.         return $code;
  767.     }
  768.     private function addInlineService(string $idDefinition $definitionDefinition $inlineDef nullbool $forConstructor true): string
  769.     {
  770.         $code '';
  771.         if ($isSimpleInstance $isRootInstance null === $inlineDef) {
  772.             foreach ($this->serviceCalls as $targetId => list($callCount$behavior$byConstructor)) {
  773.                 if ($byConstructor && isset($this->circularReferences[$id][$targetId]) && !$this->circularReferences[$id][$targetId]) {
  774.                     $code .= $this->addInlineReference($id$definition$targetId$forConstructor);
  775.                 }
  776.             }
  777.         }
  778.         if (isset($this->definitionVariables[$inlineDef $inlineDef ?: $definition])) {
  779.             return $code;
  780.         }
  781.         $arguments = [$inlineDef->getArguments(), $inlineDef->getFactory()];
  782.         $code .= $this->addInlineVariables($id$definition$arguments$forConstructor);
  783.         if ($arguments array_filter([$inlineDef->getProperties(), $inlineDef->getMethodCalls(), $inlineDef->getConfigurator()])) {
  784.             $isSimpleInstance false;
  785.         } elseif ($definition !== $inlineDef && $this->inlinedDefinitions[$inlineDef]) {
  786.             return $code;
  787.         }
  788.         if (isset($this->definitionVariables[$inlineDef])) {
  789.             $isSimpleInstance false;
  790.         } else {
  791.             $name $definition === $inlineDef 'instance' $this->getNextVariableName();
  792.             $this->definitionVariables[$inlineDef] = new Variable($name);
  793.             $code .= '' !== $code "\n" '';
  794.             if ('instance' === $name) {
  795.                 $code .= $this->addServiceInstance($id$definition$isSimpleInstance);
  796.             } else {
  797.                 $code .= $this->addNewInstance($inlineDef'        $'.$name.' = '$id);
  798.             }
  799.             if ('' !== $inline $this->addInlineVariables($id$definition$argumentsfalse)) {
  800.                 $code .= "\n".$inline."\n";
  801.             } elseif ($arguments && 'instance' === $name) {
  802.                 $code .= "\n";
  803.             }
  804.             $code .= $this->addServiceProperties($inlineDef$name);
  805.             $code .= $this->addServiceMethodCalls($inlineDef$name, !$this->getProxyDumper()->isProxyCandidate($inlineDef) && $inlineDef->isShared() && !isset($this->singleUsePrivateIds[$id]) ? $id null);
  806.             $code .= $this->addServiceConfigurator($inlineDef$name);
  807.         }
  808.         if ($isRootInstance && !$isSimpleInstance) {
  809.             $code .= "\n        return \$instance;\n";
  810.         }
  811.         return $code;
  812.     }
  813.     private function addServices(array &$services null): string
  814.     {
  815.         $publicServices $privateServices '';
  816.         $definitions $this->container->getDefinitions();
  817.         ksort($definitions);
  818.         foreach ($definitions as $id => $definition) {
  819.             if (!$definition->isSynthetic()) {
  820.                 $services[$id] = $this->addService($id$definition);
  821.             } else {
  822.                 $services[$id] = null;
  823.                 foreach ($this->getClasses($definition) as $class) {
  824.                     $this->preload[$class] = $class;
  825.                 }
  826.             }
  827.         }
  828.         foreach ($definitions as $id => $definition) {
  829.             if (!(list($file$code) = $services[$id]) || null !== $file) {
  830.                 continue;
  831.             }
  832.             if ($definition->isPublic()) {
  833.                 $publicServices .= $code;
  834.             } elseif (!$this->isTrivialInstance($definition) || isset($this->locatedIds[$id])) {
  835.                 $privateServices .= $code;
  836.             }
  837.         }
  838.         return $publicServices.$privateServices;
  839.     }
  840.     private function generateServiceFiles(array $services): iterable
  841.     {
  842.         $definitions $this->container->getDefinitions();
  843.         ksort($definitions);
  844.         foreach ($definitions as $id => $definition) {
  845.             if ((list($file$code) = $services[$id]) && null !== $file && ($definition->isPublic() || !$this->isTrivialInstance($definition) || isset($this->locatedIds[$id]))) {
  846.                 if (!$definition->isShared()) {
  847.                     $i strpos($code"\n\ninclude_once ");
  848.                     if (false !== $i && false !== $i strpos($code"\n\n"$i)) {
  849.                         $code = [substr($code0$i), substr($code$i)];
  850.                     } else {
  851.                         $code = ["\n"$code];
  852.                     }
  853.                     $code[1] = implode("\n"array_map(function ($line) { return $line '    '.$line $line; }, explode("\n"$code[1])));
  854.                     $factory sprintf('$this->factories%s[%s]'$definition->isPublic() ? '' "['service_container']"$this->doExport($id));
  855.                     $lazyloadInitialization $definition->isLazy() ? '$lazyLoad = true' '';
  856.                     $code[1] = sprintf("%s = function (%s) {\n%s};\n\nreturn %1\$s();\n"$factory$lazyloadInitialization$code[1]);
  857.                     $code $code[0].$code[1];
  858.                 }
  859.                 yield $file => $code;
  860.             }
  861.         }
  862.     }
  863.     private function addNewInstance(Definition $definitionstring $return ''string $id null): string
  864.     {
  865.         $tail $return ";\n" '';
  866.         if (BaseServiceLocator::class === $definition->getClass() && $definition->hasTag($this->serviceLocatorTag)) {
  867.             $arguments = [];
  868.             foreach ($definition->getArgument(0) as $k => $argument) {
  869.                 $arguments[$k] = $argument->getValues()[0];
  870.             }
  871.             return $return.$this->dumpValue(new ServiceLocatorArgument($arguments)).$tail;
  872.         }
  873.         $arguments = [];
  874.         foreach ($definition->getArguments() as $value) {
  875.             $arguments[] = $this->dumpValue($value);
  876.         }
  877.         if (null !== $definition->getFactory()) {
  878.             $callable $definition->getFactory();
  879.             if (\is_array($callable)) {
  880.                 if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/'$callable[1])) {
  881.                     throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s).'$callable[1] ?: 'n/a'));
  882.                 }
  883.                 if ($callable[0] instanceof Reference
  884.                     || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
  885.                     return $return.sprintf('%s->%s(%s)'$this->dumpValue($callable[0]), $callable[1], $arguments implode(', '$arguments) : '').$tail;
  886.                 }
  887.                 $class $this->dumpValue($callable[0]);
  888.                 // If the class is a string we can optimize away
  889.                 if (=== strpos($class"'") && false === strpos($class'$')) {
  890.                     if ("''" === $class) {
  891.                         throw new RuntimeException(sprintf('Cannot dump definition: %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 'The "'.$id.'"' 'inline'));
  892.                     }
  893.                     return $return.sprintf('%s::%s(%s)'$this->dumpLiteralClass($class), $callable[1], $arguments implode(', '$arguments) : '').$tail;
  894.                 }
  895.                 if (=== strpos($class'new ')) {
  896.                     return $return.sprintf('(%s)->%s(%s)'$class$callable[1], $arguments implode(', '$arguments) : '').$tail;
  897.                 }
  898.                 return $return.sprintf("[%s, '%s'](%s)"$class$callable[1], $arguments implode(', '$arguments) : '').$tail;
  899.             }
  900.             return $return.sprintf('%s(%s)'$this->dumpLiteralClass($this->dumpValue($callable)), $arguments implode(', '$arguments) : '').$tail;
  901.         }
  902.         if (null === $class $definition->getClass()) {
  903.             throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
  904.         }
  905.         return $return.sprintf('new %s(%s)'$this->dumpLiteralClass($this->dumpValue($class)), implode(', '$arguments)).$tail;
  906.     }
  907.     private function startClass(string $classstring $baseClass): string
  908.     {
  909.         $namespaceLine = !$this->asFiles && $this->namespace "\nnamespace {$this->namespace};\n" '';
  910.         $code = <<<EOF
  911. <?php
  912. $namespaceLine
  913. use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
  914. use Symfony\Component\DependencyInjection\ContainerInterface;
  915. use Symfony\Component\DependencyInjection\Container;
  916. use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
  917. use Symfony\Component\DependencyInjection\Exception\LogicException;
  918. use Symfony\Component\DependencyInjection\Exception\RuntimeException;
  919. use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
  920. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  921. /*{$this->docStar}
  922.  * This class has been auto-generated
  923.  * by the Symfony Dependency Injection Component.
  924.  *
  925.  * @final
  926.  */
  927. class $class extends $baseClass
  928. {
  929.     private \$parameters = [];
  930.     public function __construct()
  931.     {
  932. EOF;
  933.         if ($this->asFiles) {
  934.             $code str_replace('$parameters'"\$buildParameters;\n    private \$containerDir;\n    private \$parameters"$code);
  935.             $code str_replace('__construct()''__construct(array $buildParameters = [], $containerDir = __DIR__)'$code);
  936.             $code .= "        \$this->buildParameters = \$buildParameters;\n";
  937.             $code .= "        \$this->containerDir = \$containerDir;\n";
  938.             if (null !== $this->targetDirRegex) {
  939.                 $code str_replace('$parameters'"\$targetDir;\n    private \$parameters"$code);
  940.                 $code .= '        $this->targetDir = \\dirname($containerDir);'."\n";
  941.             }
  942.         }
  943.         if (Container::class !== $this->baseClass) {
  944.             $r $this->container->getReflectionClass($this->baseClassfalse);
  945.             if (null !== $r
  946.                 && (null !== $constructor $r->getConstructor())
  947.                 && === $constructor->getNumberOfRequiredParameters()
  948.                 && Container::class !== $constructor->getDeclaringClass()->name
  949.             ) {
  950.                 $code .= "        parent::__construct();\n";
  951.                 $code .= "        \$this->parameterBag = null;\n\n";
  952.             }
  953.         }
  954.         if ($this->container->getParameterBag()->all()) {
  955.             $code .= "        \$this->parameters = \$this->getDefaultParameters();\n\n";
  956.         }
  957.         $code .= "        \$this->services = \$this->privates = [];\n";
  958.         $code .= $this->addSyntheticIds();
  959.         $code .= $this->addMethodMap();
  960.         $code .= $this->asFiles && !$this->inlineFactories $this->addFileMap() : '';
  961.         $code .= $this->addAliases();
  962.         $code .= $this->addInlineRequires();
  963.         $code .= <<<EOF
  964.     }
  965.     public function compile(): void
  966.     {
  967.         throw new LogicException('You cannot compile a dumped container that was already compiled.');
  968.     }
  969.     public function isCompiled(): bool
  970.     {
  971.         return true;
  972.     }
  973. EOF;
  974.         $code .= $this->addRemovedIds();
  975.         if ($this->asFiles && !$this->inlineFactories) {
  976.             $code .= <<<EOF
  977.     protected function load(\$file, \$lazyLoad = true)
  978.     {
  979.         return require \$this->containerDir.\\DIRECTORY_SEPARATOR.\$file;
  980.     }
  981. EOF;
  982.         }
  983.         $proxyDumper $this->getProxyDumper();
  984.         foreach ($this->container->getDefinitions() as $definition) {
  985.             if (!$proxyDumper->isProxyCandidate($definition)) {
  986.                 continue;
  987.             }
  988.             if ($this->asFiles && !$this->inlineFactories) {
  989.                 $proxyLoader '$this->load("{$class}.php")';
  990.             } elseif ($this->namespace || $this->inlineFactories) {
  991.                 $proxyLoader 'class_alias(__NAMESPACE__."\\\\$class", $class, false)';
  992.             } else {
  993.                 $proxyLoader '';
  994.             }
  995.             if ($proxyLoader) {
  996.                 $proxyLoader "class_exists(\$class, false) || {$proxyLoader};\n\n        ";
  997.             }
  998.             $code .= <<<EOF
  999.     protected function createProxy(\$class, \Closure \$factory)
  1000.     {
  1001.         {$proxyLoader}return \$factory();
  1002.     }
  1003. EOF;
  1004.             break;
  1005.         }
  1006.         return $code;
  1007.     }
  1008.     private function addSyntheticIds(): string
  1009.     {
  1010.         $code '';
  1011.         $definitions $this->container->getDefinitions();
  1012.         ksort($definitions);
  1013.         foreach ($definitions as $id => $definition) {
  1014.             if ($definition->isSynthetic() && 'service_container' !== $id) {
  1015.                 $code .= '            '.$this->doExport($id)." => true,\n";
  1016.             }
  1017.         }
  1018.         return $code "        \$this->syntheticIds = [\n{$code}        ];\n" '';
  1019.     }
  1020.     private function addRemovedIds(): string
  1021.     {
  1022.         $ids $this->container->getRemovedIds();
  1023.         foreach ($this->container->getDefinitions() as $id => $definition) {
  1024.             if (!$definition->isPublic()) {
  1025.                 $ids[$id] = true;
  1026.             }
  1027.         }
  1028.         if (!$ids) {
  1029.             return '';
  1030.         }
  1031.         if ($this->asFiles) {
  1032.             $code "require \$this->containerDir.\\DIRECTORY_SEPARATOR.'removed-ids.php'";
  1033.         } else {
  1034.             $code '';
  1035.             $ids array_keys($ids);
  1036.             sort($ids);
  1037.             foreach ($ids as $id) {
  1038.                 if (preg_match(FileLoader::ANONYMOUS_ID_REGEXP$id)) {
  1039.                     continue;
  1040.                 }
  1041.                 $code .= '            '.$this->doExport($id)." => true,\n";
  1042.             }
  1043.             $code "[\n{$code}        ]";
  1044.         }
  1045.         return <<<EOF
  1046.     public function getRemovedIds(): array
  1047.     {
  1048.         return {$code};
  1049.     }
  1050. EOF;
  1051.     }
  1052.     private function addMethodMap(): string
  1053.     {
  1054.         $code '';
  1055.         $definitions $this->container->getDefinitions();
  1056.         ksort($definitions);
  1057.         foreach ($definitions as $id => $definition) {
  1058.             if (!$definition->isSynthetic() && $definition->isPublic() && (!$this->asFiles || $this->inlineFactories || $this->isHotPath($definition))) {
  1059.                 $code .= '            '.$this->doExport($id).' => '.$this->doExport($this->generateMethodName($id)).",\n";
  1060.             }
  1061.         }
  1062.         $aliases $this->container->getAliases();
  1063.         foreach ($aliases as $alias => $id) {
  1064.             if (!$id->isDeprecated()) {
  1065.                 continue;
  1066.             }
  1067.             $code .= '            '.$this->doExport($alias).' => '.$this->doExport($this->generateMethodName($alias)).",\n";
  1068.         }
  1069.         return $code "        \$this->methodMap = [\n{$code}        ];\n" '';
  1070.     }
  1071.     private function addFileMap(): string
  1072.     {
  1073.         $code '';
  1074.         $definitions $this->container->getDefinitions();
  1075.         ksort($definitions);
  1076.         foreach ($definitions as $id => $definition) {
  1077.             if (!$definition->isSynthetic() && $definition->isPublic() && !$this->isHotPath($definition)) {
  1078.                 $code .= sprintf("            %s => '%s.php',\n"$this->doExport($id), $this->generateMethodName($id));
  1079.             }
  1080.         }
  1081.         return $code "        \$this->fileMap = [\n{$code}        ];\n" '';
  1082.     }
  1083.     private function addAliases(): string
  1084.     {
  1085.         if (!$aliases $this->container->getAliases()) {
  1086.             return "\n        \$this->aliases = [];\n";
  1087.         }
  1088.         $code "        \$this->aliases = [\n";
  1089.         ksort($aliases);
  1090.         foreach ($aliases as $alias => $id) {
  1091.             if ($id->isDeprecated()) {
  1092.                 continue;
  1093.             }
  1094.             $id = (string) $id;
  1095.             while (isset($aliases[$id])) {
  1096.                 $id = (string) $aliases[$id];
  1097.             }
  1098.             $code .= '            '.$this->doExport($alias).' => '.$this->doExport($id).",\n";
  1099.         }
  1100.         return $code."        ];\n";
  1101.     }
  1102.     private function addDeprecatedAliases(): string
  1103.     {
  1104.         $code '';
  1105.         $aliases $this->container->getAliases();
  1106.         foreach ($aliases as $alias => $definition) {
  1107.             if (!$definition->isDeprecated()) {
  1108.                 continue;
  1109.             }
  1110.             $public $definition->isPublic() ? 'public' 'private';
  1111.             $id = (string) $definition;
  1112.             $methodNameAlias $this->generateMethodName($alias);
  1113.             $idExported $this->export($id);
  1114.             $messageExported $this->export($definition->getDeprecationMessage($alias));
  1115.             $code .= <<<EOF
  1116.     /*{$this->docStar}
  1117.      * Gets the $public '$alias' alias.
  1118.      *
  1119.      * @return object The "$id" service.
  1120.      */
  1121.     protected function {$methodNameAlias}()
  1122.     {
  1123.         @trigger_error($messageExported, E_USER_DEPRECATED);
  1124.         return \$this->get($idExported);
  1125.     }
  1126. EOF;
  1127.         }
  1128.         return $code;
  1129.     }
  1130.     private function addInlineRequires(): string
  1131.     {
  1132.         if (!$this->hotPathTag || !$this->inlineRequires) {
  1133.             return '';
  1134.         }
  1135.         $lineage = [];
  1136.         foreach ($this->container->findTaggedServiceIds($this->hotPathTag) as $id => $tags) {
  1137.             $definition $this->container->getDefinition($id);
  1138.             if ($this->getProxyDumper()->isProxyCandidate($definition)) {
  1139.                 continue;
  1140.             }
  1141.             $inlinedDefinitions $this->getDefinitionsFromArguments([$definition]);
  1142.             foreach ($inlinedDefinitions as $def) {
  1143.                 foreach ($this->getClasses($def) as $class) {
  1144.                     $this->collectLineage($class$lineage);
  1145.                 }
  1146.             }
  1147.         }
  1148.         $code '';
  1149.         foreach ($lineage as $file) {
  1150.             if (!isset($this->inlinedRequires[$file])) {
  1151.                 $this->inlinedRequires[$file] = true;
  1152.                 $code .= sprintf("\n            include_once %s;"$file);
  1153.             }
  1154.         }
  1155.         return $code sprintf("\n        \$this->privates['service_container'] = function () {%s\n        };\n"$code) : '';
  1156.     }
  1157.     private function addDefaultParametersMethod(): string
  1158.     {
  1159.         if (!$this->container->getParameterBag()->all()) {
  1160.             return '';
  1161.         }
  1162.         $php = [];
  1163.         $dynamicPhp = [];
  1164.         foreach ($this->container->getParameterBag()->all() as $key => $value) {
  1165.             if ($key !== $resolvedKey $this->container->resolveEnvPlaceholders($key)) {
  1166.                 throw new InvalidArgumentException(sprintf('Parameter name cannot use env parameters: "%s".'$resolvedKey));
  1167.             }
  1168.             $export $this->exportParameters([$value]);
  1169.             $export explode('0 => 'substr(rtrim($export" ]\n"), 2, -1), 2);
  1170.             if (preg_match("/\\\$this->(?:getEnv\('(?:\w++:)*+\w++'\)|targetDir\.'')/"$export[1])) {
  1171.                 $dynamicPhp[$key] = sprintf('%scase %s: $value = %s; break;'$export[0], $this->export($key), $export[1]);
  1172.             } else {
  1173.                 $php[] = sprintf('%s%s => %s,'$export[0], $this->export($key), $export[1]);
  1174.             }
  1175.         }
  1176.         $parameters sprintf("[\n%s\n%s]"implode("\n"$php), str_repeat(' '8));
  1177.         $code = <<<'EOF'
  1178.     public function getParameter($name)
  1179.     {
  1180.         $name = (string) $name;
  1181.         if (isset($this->buildParameters[$name])) {
  1182.             return $this->buildParameters[$name];
  1183.         }
  1184.         if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) {
  1185.             throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
  1186.         }
  1187.         if (isset($this->loadedDynamicParameters[$name])) {
  1188.             return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
  1189.         }
  1190.         return $this->parameters[$name];
  1191.     }
  1192.     public function hasParameter($name): bool
  1193.     {
  1194.         $name = (string) $name;
  1195.         if (isset($this->buildParameters[$name])) {
  1196.             return true;
  1197.         }
  1198.         return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters);
  1199.     }
  1200.     public function setParameter($name, $value): void
  1201.     {
  1202.         throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
  1203.     }
  1204.     public function getParameterBag(): ParameterBagInterface
  1205.     {
  1206.         if (null === $this->parameterBag) {
  1207.             $parameters = $this->parameters;
  1208.             foreach ($this->loadedDynamicParameters as $name => $loaded) {
  1209.                 $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name);
  1210.             }
  1211.             foreach ($this->buildParameters as $name => $value) {
  1212.                 $parameters[$name] = $value;
  1213.             }
  1214.             $this->parameterBag = new FrozenParameterBag($parameters);
  1215.         }
  1216.         return $this->parameterBag;
  1217.     }
  1218. EOF;
  1219.         if (!$this->asFiles) {
  1220.             $code preg_replace('/^.*buildParameters.*\n.*\n.*\n/m'''$code);
  1221.         }
  1222.         if ($dynamicPhp) {
  1223.             $loadedDynamicParameters $this->exportParameters(array_combine(array_keys($dynamicPhp), array_fill(0, \count($dynamicPhp), false)), ''8);
  1224.             $getDynamicParameter = <<<'EOF'
  1225.         switch ($name) {
  1226. %s
  1227.             default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%%s" must be defined.', $name));
  1228.         }
  1229.         $this->loadedDynamicParameters[$name] = true;
  1230.         return $this->dynamicParameters[$name] = $value;
  1231. EOF;
  1232.             $getDynamicParameter sprintf($getDynamicParameterimplode("\n"$dynamicPhp));
  1233.         } else {
  1234.             $loadedDynamicParameters '[]';
  1235.             $getDynamicParameter str_repeat(' '8).'throw new InvalidArgumentException(sprintf(\'The dynamic parameter "%s" must be defined.\', $name));';
  1236.         }
  1237.         $code .= <<<EOF
  1238.     private \$loadedDynamicParameters = {$loadedDynamicParameters};
  1239.     private \$dynamicParameters = [];
  1240.     private function getDynamicParameter(string \$name)
  1241.     {
  1242. {$getDynamicParameter}
  1243.     }
  1244.     protected function getDefaultParameters(): array
  1245.     {
  1246.         return $parameters;
  1247.     }
  1248. EOF;
  1249.         return $code;
  1250.     }
  1251.     /**
  1252.      * @throws InvalidArgumentException
  1253.      */
  1254.     private function exportParameters(array $parametersstring $path ''int $indent 12): string
  1255.     {
  1256.         $php = [];
  1257.         foreach ($parameters as $key => $value) {
  1258.             if (\is_array($value)) {
  1259.                 $value $this->exportParameters($value$path.'/'.$key$indent 4);
  1260.             } elseif ($value instanceof ArgumentInterface) {
  1261.                 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain special arguments. "%s" found in "%s".', \get_class($value), $path.'/'.$key));
  1262.             } elseif ($value instanceof Variable) {
  1263.                 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".'$value$path.'/'.$key));
  1264.             } elseif ($value instanceof Definition) {
  1265.                 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));
  1266.             } elseif ($value instanceof Reference) {
  1267.                 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));
  1268.             } elseif ($value instanceof Expression) {
  1269.                 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain expressions. Expression "%s" found in "%s".'$value$path.'/'.$key));
  1270.             } else {
  1271.                 $value $this->export($value);
  1272.             }
  1273.             $php[] = sprintf('%s%s => %s,'str_repeat(' '$indent), $this->export($key), $value);
  1274.         }
  1275.         return sprintf("[\n%s\n%s]"implode("\n"$php), str_repeat(' '$indent 4));
  1276.     }
  1277.     private function endClass(): string
  1278.     {
  1279.         if ($this->addThrow) {
  1280.             return <<<'EOF'
  1281.     protected function throw($message)
  1282.     {
  1283.         throw new RuntimeException($message);
  1284.     }
  1285. }
  1286. EOF;
  1287.         }
  1288.         return <<<'EOF'
  1289. }
  1290. EOF;
  1291.     }
  1292.     private function wrapServiceConditionals($valuestring $code): string
  1293.     {
  1294.         if (!$condition $this->getServiceConditionals($value)) {
  1295.             return $code;
  1296.         }
  1297.         // re-indent the wrapped code
  1298.         $code implode("\n"array_map(function ($line) { return $line '    '.$line $line; }, explode("\n"$code)));
  1299.         return sprintf("        if (%s) {\n%s        }\n"$condition$code);
  1300.     }
  1301.     private function getServiceConditionals($value): string
  1302.     {
  1303.         $conditions = [];
  1304.         foreach (ContainerBuilder::getInitializedConditionals($value) as $service) {
  1305.             if (!$this->container->hasDefinition($service)) {
  1306.                 return 'false';
  1307.             }
  1308.             $conditions[] = sprintf('isset($this->%s[%s])'$this->container->getDefinition($service)->isPublic() ? 'services' 'privates'$this->doExport($service));
  1309.         }
  1310.         foreach (ContainerBuilder::getServiceConditionals($value) as $service) {
  1311.             if ($this->container->hasDefinition($service) && !$this->container->getDefinition($service)->isPublic()) {
  1312.                 continue;
  1313.             }
  1314.             $conditions[] = sprintf('$this->has(%s)'$this->doExport($service));
  1315.         }
  1316.         if (!$conditions) {
  1317.             return '';
  1318.         }
  1319.         return implode(' && '$conditions);
  1320.     }
  1321.     private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions null, array &$calls = [], bool $byConstructor null): \SplObjectStorage
  1322.     {
  1323.         if (null === $definitions) {
  1324.             $definitions = new \SplObjectStorage();
  1325.         }
  1326.         foreach ($arguments as $argument) {
  1327.             if (\is_array($argument)) {
  1328.                 $this->getDefinitionsFromArguments($argument$definitions$calls$byConstructor);
  1329.             } elseif ($argument instanceof Reference) {
  1330.                 $id = (string) $argument;
  1331.                 while ($this->container->hasAlias($id)) {
  1332.                     $id = (string) $this->container->getAlias($id);
  1333.                 }
  1334.                 if (!isset($calls[$id])) {
  1335.                     $calls[$id] = [0$argument->getInvalidBehavior(), $byConstructor];
  1336.                 } else {
  1337.                     $calls[$id][1] = min($calls[$id][1], $argument->getInvalidBehavior());
  1338.                 }
  1339.                 ++$calls[$id][0];
  1340.             } elseif (!$argument instanceof Definition) {
  1341.                 // no-op
  1342.             } elseif (isset($definitions[$argument])) {
  1343.                 $definitions[$argument] = $definitions[$argument];
  1344.             } else {
  1345.                 $definitions[$argument] = 1;
  1346.                 $arguments = [$argument->getArguments(), $argument->getFactory()];
  1347.                 $this->getDefinitionsFromArguments($arguments$definitions$callsnull === $byConstructor || $byConstructor);
  1348.                 $arguments = [$argument->getProperties(), $argument->getMethodCalls(), $argument->getConfigurator()];
  1349.                 $this->getDefinitionsFromArguments($arguments$definitions$callsnull !== $byConstructor && $byConstructor);
  1350.             }
  1351.         }
  1352.         return $definitions;
  1353.     }
  1354.     /**
  1355.      * @throws RuntimeException
  1356.      */
  1357.     private function dumpValue($valuebool $interpolate true): string
  1358.     {
  1359.         if (\is_array($value)) {
  1360.             if ($value && $interpolate && false !== $param array_search($value$this->container->getParameterBag()->all(), true)) {
  1361.                 return $this->dumpValue("%$param%");
  1362.             }
  1363.             $code = [];
  1364.             foreach ($value as $k => $v) {
  1365.                 $code[] = sprintf('%s => %s'$this->dumpValue($k$interpolate), $this->dumpValue($v$interpolate));
  1366.             }
  1367.             return sprintf('[%s]'implode(', '$code));
  1368.         } elseif ($value instanceof ArgumentInterface) {
  1369.             $scope = [$this->definitionVariables$this->referenceVariables];
  1370.             $this->definitionVariables $this->referenceVariables null;
  1371.             try {
  1372.                 if ($value instanceof ServiceClosureArgument) {
  1373.                     $value $value->getValues()[0];
  1374.                     $code $this->dumpValue($value$interpolate);
  1375.                     $returnedType '';
  1376.                     if ($value instanceof TypedReference) {
  1377.                         $returnedType sprintf(': %s\%s'ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $value->getInvalidBehavior() ? '' '?'$value->getType());
  1378.                     }
  1379.                     $code sprintf('return %s;'$code);
  1380.                     return sprintf("function ()%s {\n            %s\n        }"$returnedType$code);
  1381.                 }
  1382.                 if ($value instanceof IteratorArgument) {
  1383.                     $operands = [0];
  1384.                     $code = [];
  1385.                     $code[] = 'new RewindableGenerator(function () {';
  1386.                     if (!$values $value->getValues()) {
  1387.                         $code[] = '            return new \EmptyIterator();';
  1388.                     } else {
  1389.                         $countCode = [];
  1390.                         $countCode[] = 'function () {';
  1391.                         foreach ($values as $k => $v) {
  1392.                             ($c $this->getServiceConditionals($v)) ? $operands[] = "(int) ($c)" : ++$operands[0];
  1393.                             $v $this->wrapServiceConditionals($vsprintf("        yield %s => %s;\n"$this->dumpValue($k$interpolate), $this->dumpValue($v$interpolate)));
  1394.                             foreach (explode("\n"$v) as $v) {
  1395.                                 if ($v) {
  1396.                                     $code[] = '    '.$v;
  1397.                                 }
  1398.                             }
  1399.                         }
  1400.                         $countCode[] = sprintf('            return %s;'implode(' + '$operands));
  1401.                         $countCode[] = '        }';
  1402.                     }
  1403.                     $code[] = sprintf('        }, %s)', \count($operands) > implode("\n"$countCode) : $operands[0]);
  1404.                     return implode("\n"$code);
  1405.                 }
  1406.                 if ($value instanceof ServiceLocatorArgument) {
  1407.                     $serviceMap '';
  1408.                     $serviceTypes '';
  1409.                     foreach ($value->getValues() as $k => $v) {
  1410.                         if (!$v) {
  1411.                             continue;
  1412.                         }
  1413.                         $definition $this->container->findDefinition($id = (string) $v);
  1414.                         $load = !($definition->hasErrors() && $e $definition->getErrors()) ? $this->asFiles && !$this->inlineFactories && !$this->isHotPath($definition) : reset($e);
  1415.                         $serviceMap .= sprintf("\n            %s => [%s, %s, %s, %s],",
  1416.                             $this->export($k),
  1417.                             $this->export($definition->isShared() ? ($definition->isPublic() ? 'services' 'privates') : false),
  1418.                             $this->doExport($id),
  1419.                             $this->export(ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $v->getInvalidBehavior() && !\is_string($load) ? $this->generateMethodName($id).($load '.php' '') : null),
  1420.                             $this->export($load)
  1421.                         );
  1422.                         $serviceTypes .= sprintf("\n            %s => %s,"$this->export($k), $this->export($v instanceof TypedReference $v->getType() : '?'));
  1423.                         $this->locatedIds[$id] = true;
  1424.                     }
  1425.                     $this->addGetService true;
  1426.                     return sprintf('new \%s($this->getService, [%s%s], [%s%s])'ServiceLocator::class, $serviceMap$serviceMap "\n        " ''$serviceTypes$serviceTypes "\n        " '');
  1427.                 }
  1428.             } finally {
  1429.                 list($this->definitionVariables$this->referenceVariables) = $scope;
  1430.             }
  1431.         } elseif ($value instanceof Definition) {
  1432.             if ($value->hasErrors() && $e $value->getErrors()) {
  1433.                 $this->addThrow true;
  1434.                 return sprintf('$this->throw(%s)'$this->export(reset($e)));
  1435.             }
  1436.             if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {
  1437.                 return $this->dumpValue($this->definitionVariables[$value], $interpolate);
  1438.             }
  1439.             if ($value->getMethodCalls()) {
  1440.                 throw new RuntimeException('Cannot dump definitions which have method calls.');
  1441.             }
  1442.             if ($value->getProperties()) {
  1443.                 throw new RuntimeException('Cannot dump definitions which have properties.');
  1444.             }
  1445.             if (null !== $value->getConfigurator()) {
  1446.                 throw new RuntimeException('Cannot dump definitions which have a configurator.');
  1447.             }
  1448.             return $this->addNewInstance($value);
  1449.         } elseif ($value instanceof Variable) {
  1450.             return '$'.$value;
  1451.         } elseif ($value instanceof Reference) {
  1452.             $id = (string) $value;
  1453.             while ($this->container->hasAlias($id)) {
  1454.                 $id = (string) $this->container->getAlias($id);
  1455.             }
  1456.             if (null !== $this->referenceVariables && isset($this->referenceVariables[$id])) {
  1457.                 return $this->dumpValue($this->referenceVariables[$id], $interpolate);
  1458.             }
  1459.             return $this->getServiceCall($id$value);
  1460.         } elseif ($value instanceof Expression) {
  1461.             return $this->getExpressionLanguage()->compile((string) $value, ['this' => 'container']);
  1462.         } elseif ($value instanceof Parameter) {
  1463.             return $this->dumpParameter($value);
  1464.         } elseif (true === $interpolate && \is_string($value)) {
  1465.             if (preg_match('/^%([^%]+)%$/'$value$match)) {
  1466.                 // we do this to deal with non string values (Boolean, integer, ...)
  1467.                 // the preg_replace_callback converts them to strings
  1468.                 return $this->dumpParameter($match[1]);
  1469.             } else {
  1470.                 $replaceParameters = function ($match) {
  1471.                     return "'.".$this->dumpParameter($match[2]).".'";
  1472.                 };
  1473.                 $code str_replace('%%''%'preg_replace_callback('/(?<!%)(%)([^%]+)\1/'$replaceParameters$this->export($value)));
  1474.                 return $code;
  1475.             }
  1476.         } elseif (\is_object($value) || \is_resource($value)) {
  1477.             throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
  1478.         }
  1479.         return $this->export($value);
  1480.     }
  1481.     /**
  1482.      * Dumps a string to a literal (aka PHP Code) class value.
  1483.      *
  1484.      * @throws RuntimeException
  1485.      */
  1486.     private function dumpLiteralClass(string $class): string
  1487.     {
  1488.         if (false !== strpos($class'$')) {
  1489.             return sprintf('${($_ = %s) && false ?: "_"}'$class);
  1490.         }
  1491.         if (!== 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)) {
  1492.             throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s).'$class ?: 'n/a'));
  1493.         }
  1494.         $class substr(str_replace('\\\\''\\'$class), 1, -1);
  1495.         return === strpos($class'\\') ? $class '\\'.$class;
  1496.     }
  1497.     private function dumpParameter(string $name): string
  1498.     {
  1499.         if ($this->container->hasParameter($name)) {
  1500.             $value $this->container->getParameter($name);
  1501.             $dumpedValue $this->dumpValue($valuefalse);
  1502.             if (!$value || !\is_array($value)) {
  1503.                 return $dumpedValue;
  1504.             }
  1505.             if (!preg_match("/\\\$this->(?:getEnv\('(?:\w++:)*+\w++'\)|targetDir\.'')/"$dumpedValue)) {
  1506.                 return sprintf('$this->parameters[%s]'$this->doExport($name));
  1507.             }
  1508.         }
  1509.         return sprintf('$this->getParameter(%s)'$this->doExport($name));
  1510.     }
  1511.     private function getServiceCall(string $idReference $reference null): string
  1512.     {
  1513.         while ($this->container->hasAlias($id)) {
  1514.             $id = (string) $this->container->getAlias($id);
  1515.         }
  1516.         if ('service_container' === $id) {
  1517.             return '$this';
  1518.         }
  1519.         if ($this->container->hasDefinition($id) && $definition $this->container->getDefinition($id)) {
  1520.             if ($definition->isSynthetic()) {
  1521.                 $code sprintf('$this->get(%s%s)'$this->doExport($id), null !== $reference ', '.$reference->getInvalidBehavior() : '');
  1522.             } elseif (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) {
  1523.                 $code 'null';
  1524.                 if (!$definition->isShared()) {
  1525.                     return $code;
  1526.                 }
  1527.             } elseif ($this->isTrivialInstance($definition)) {
  1528.                 if ($definition->hasErrors() && $e $definition->getErrors()) {
  1529.                     $this->addThrow true;
  1530.                     return sprintf('$this->throw(%s)'$this->export(reset($e)));
  1531.                 }
  1532.                 $code $this->addNewInstance($definition''$id);
  1533.                 if ($definition->isShared() && !isset($this->singleUsePrivateIds[$id])) {
  1534.                     $code sprintf('$this->%s[%s] = %s'$definition->isPublic() ? 'services' 'privates'$this->doExport($id), $code);
  1535.                 }
  1536.                 $code "($code)";
  1537.             } elseif ($this->asFiles && !$this->inlineFactories && !$this->isHotPath($definition)) {
  1538.                 $code sprintf("\$this->load('%s.php')"$this->generateMethodName($id));
  1539.                 if (!$definition->isShared()) {
  1540.                     $factory sprintf('$this->factories%s[%s]'$definition->isPublic() ? '' "['service_container']"$this->doExport($id));
  1541.                     $code sprintf('(isset(%s) ? %1$s() : %s)'$factory$code);
  1542.                 }
  1543.             } else {
  1544.                 $code sprintf('$this->%s()'$this->generateMethodName($id));
  1545.             }
  1546.             if ($definition->isShared() && !isset($this->singleUsePrivateIds[$id])) {
  1547.                 $code sprintf('($this->%s[%s] ?? %s)'$definition->isPublic() ? 'services' 'privates'$this->doExport($id), $code);
  1548.             }
  1549.             return $code;
  1550.         }
  1551.         if (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) {
  1552.             return 'null';
  1553.         }
  1554.         if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE $reference->getInvalidBehavior()) {
  1555.             $code sprintf('$this->get(%s, /* ContainerInterface::NULL_ON_INVALID_REFERENCE */ %d)'$this->doExport($id), ContainerInterface::NULL_ON_INVALID_REFERENCE);
  1556.         } else {
  1557.             $code sprintf('$this->get(%s)'$this->doExport($id));
  1558.         }
  1559.         return sprintf('($this->services[%s] ?? %s)'$this->doExport($id), $code);
  1560.     }
  1561.     /**
  1562.      * Initializes the method names map to avoid conflicts with the Container methods.
  1563.      */
  1564.     private function initializeMethodNamesMap(string $class)
  1565.     {
  1566.         $this->serviceIdToMethodNameMap = [];
  1567.         $this->usedMethodNames = [];
  1568.         if ($reflectionClass $this->container->getReflectionClass($class)) {
  1569.             foreach ($reflectionClass->getMethods() as $method) {
  1570.                 $this->usedMethodNames[strtolower($method->getName())] = true;
  1571.             }
  1572.         }
  1573.     }
  1574.     /**
  1575.      * @throws InvalidArgumentException
  1576.      */
  1577.     private function generateMethodName(string $id): string
  1578.     {
  1579.         if (isset($this->serviceIdToMethodNameMap[$id])) {
  1580.             return $this->serviceIdToMethodNameMap[$id];
  1581.         }
  1582.         $i strrpos($id'\\');
  1583.         $name Container::camelize(false !== $i && isset($id[$i]) ? substr($id$i) : $id);
  1584.         $name preg_replace('/[^a-zA-Z0-9_\x7f-\xff]/'''$name);
  1585.         $methodName 'get'.$name.'Service';
  1586.         $suffix 1;
  1587.         while (isset($this->usedMethodNames[strtolower($methodName)])) {
  1588.             ++$suffix;
  1589.             $methodName 'get'.$name.$suffix.'Service';
  1590.         }
  1591.         $this->serviceIdToMethodNameMap[$id] = $methodName;
  1592.         $this->usedMethodNames[strtolower($methodName)] = true;
  1593.         return $methodName;
  1594.     }
  1595.     private function getNextVariableName(): string
  1596.     {
  1597.         $firstChars self::FIRST_CHARS;
  1598.         $firstCharsLength = \strlen($firstChars);
  1599.         $nonFirstChars self::NON_FIRST_CHARS;
  1600.         $nonFirstCharsLength = \strlen($nonFirstChars);
  1601.         while (true) {
  1602.             $name '';
  1603.             $i $this->variableCount;
  1604.             if ('' === $name) {
  1605.                 $name .= $firstChars[$i $firstCharsLength];
  1606.                 $i = (int) ($i $firstCharsLength);
  1607.             }
  1608.             while ($i 0) {
  1609.                 --$i;
  1610.                 $name .= $nonFirstChars[$i $nonFirstCharsLength];
  1611.                 $i = (int) ($i $nonFirstCharsLength);
  1612.             }
  1613.             ++$this->variableCount;
  1614.             // check that the name is not reserved
  1615.             if (\in_array($name$this->reservedVariablestrue)) {
  1616.                 continue;
  1617.             }
  1618.             return $name;
  1619.         }
  1620.     }
  1621.     private function getExpressionLanguage(): ExpressionLanguage
  1622.     {
  1623.         if (null === $this->expressionLanguage) {
  1624.             if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
  1625.                 throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
  1626.             }
  1627.             $providers $this->container->getExpressionLanguageProviders();
  1628.             $this->expressionLanguage = new ExpressionLanguage(null$providers, function ($arg) {
  1629.                 $id '""' === substr_replace($arg''1, -1) ? stripcslashes(substr($arg1, -1)) : null;
  1630.                 if (null !== $id && ($this->container->hasAlias($id) || $this->container->hasDefinition($id))) {
  1631.                     return $this->getServiceCall($id);
  1632.                 }
  1633.                 return sprintf('$this->get(%s)'$arg);
  1634.             });
  1635.             if ($this->container->isTrackingResources()) {
  1636.                 foreach ($providers as $provider) {
  1637.                     $this->container->addObjectResource($provider);
  1638.                 }
  1639.             }
  1640.         }
  1641.         return $this->expressionLanguage;
  1642.     }
  1643.     private function isHotPath(Definition $definition): bool
  1644.     {
  1645.         return $this->hotPathTag && $definition->hasTag($this->hotPathTag) && !$definition->isDeprecated();
  1646.     }
  1647.     private function isSingleUsePrivateNode(ServiceReferenceGraphNode $node): bool
  1648.     {
  1649.         if ($node->getValue()->isPublic()) {
  1650.             return false;
  1651.         }
  1652.         $ids = [];
  1653.         foreach ($node->getInEdges() as $edge) {
  1654.             if (!$value $edge->getSourceNode()->getValue()) {
  1655.                 continue;
  1656.             }
  1657.             if ($edge->isLazy() || !$value instanceof Definition || !$value->isShared()) {
  1658.                 return false;
  1659.             }
  1660.             $ids[$edge->getSourceNode()->getId()] = true;
  1661.         }
  1662.         return === \count($ids);
  1663.     }
  1664.     /**
  1665.      * @return mixed
  1666.      */
  1667.     private function export($value)
  1668.     {
  1669.         if (null !== $this->targetDirRegex && \is_string($value) && preg_match($this->targetDirRegex$value$matchesPREG_OFFSET_CAPTURE)) {
  1670.             $prefix $matches[0][1] ? $this->doExport(substr($value0$matches[0][1]), true).'.' '';
  1671.             $suffix $matches[0][1] + \strlen($matches[0][0]);
  1672.             $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value$suffix), true) : '';
  1673.             $dirname $this->asFiles '$this->containerDir' '__DIR__';
  1674.             $offset $this->targetDirMaxMatches - \count($matches);
  1675.             if ($offset) {
  1676.                 $dirname sprintf('\dirname(__DIR__, %d)'$offset + (int) $this->asFiles);
  1677.             } elseif ($this->asFiles) {
  1678.                 $dirname "\$this->targetDir.''"// empty string concatenation on purpose
  1679.             }
  1680.             if ($prefix || $suffix) {
  1681.                 return sprintf('(%s%s%s)'$prefix$dirname$suffix);
  1682.             }
  1683.             return $dirname;
  1684.         }
  1685.         return $this->doExport($valuetrue);
  1686.     }
  1687.     /**
  1688.      * @return mixed
  1689.      */
  1690.     private function doExport($valuebool $resolveEnv false)
  1691.     {
  1692.         $shouldCacheValue $resolveEnv && \is_string($value);
  1693.         if ($shouldCacheValue && isset($this->exportedVariables[$value])) {
  1694.             return $this->exportedVariables[$value];
  1695.         }
  1696.         if (\is_string($value) && false !== strpos($value"\n")) {
  1697.             $cleanParts explode("\n"$value);
  1698.             $cleanParts array_map(function ($part) { return var_export($parttrue); }, $cleanParts);
  1699.             $export implode('."\n".'$cleanParts);
  1700.         } else {
  1701.             $export var_export($valuetrue);
  1702.         }
  1703.         if ($resolveEnv && "'" === $export[0] && $export !== $resolvedExport $this->container->resolveEnvPlaceholders($export"'.\$this->getEnv('string:%s').'")) {
  1704.             $export $resolvedExport;
  1705.             if (".''" === substr($export, -3)) {
  1706.                 $export substr($export0, -3);
  1707.                 if ("'" === $export[1]) {
  1708.                     $export substr_replace($export''187);
  1709.                 }
  1710.             }
  1711.             if ("'" === $export[1]) {
  1712.                 $export substr($export3);
  1713.             }
  1714.         }
  1715.         if ($shouldCacheValue) {
  1716.             $this->exportedVariables[$value] = $export;
  1717.         }
  1718.         return $export;
  1719.     }
  1720.     private function getAutoloadFile(): ?string
  1721.     {
  1722.         if (null === $this->targetDirRegex) {
  1723.             return null;
  1724.         }
  1725.         foreach (spl_autoload_functions() as $autoloader) {
  1726.             if (!\is_array($autoloader)) {
  1727.                 continue;
  1728.             }
  1729.             if ($autoloader[0] instanceof DebugClassLoader || $autoloader[0] instanceof LegacyDebugClassLoader) {
  1730.                 $autoloader $autoloader[0]->getClassLoader();
  1731.             }
  1732.             if (!\is_array($autoloader) || !$autoloader[0] instanceof ClassLoader || !$autoloader[0]->findFile(__CLASS__)) {
  1733.                 continue;
  1734.             }
  1735.             foreach (get_declared_classes() as $class) {
  1736.                 if (=== strpos($class'ComposerAutoloaderInit') && $class::getLoader() === $autoloader[0]) {
  1737.                     $file = \dirname((new \ReflectionClass($class))->getFileName(), 2).'/autoload.php';
  1738.                     if (preg_match($this->targetDirRegex.'A'$file)) {
  1739.                         return $file;
  1740.                     }
  1741.                 }
  1742.             }
  1743.         }
  1744.         return null;
  1745.     }
  1746.     private function getClasses(Definition $definition): array
  1747.     {
  1748.         $classes = [];
  1749.         while ($definition instanceof Definition) {
  1750.             $classes[] = trim($definition->getClass(), '\\');
  1751.             $factory $definition->getFactory();
  1752.             if (!\is_array($factory)) {
  1753.                 $factory = [$factory];
  1754.             }
  1755.             if (\is_string($factory[0])) {
  1756.                 if (false !== $i strrpos($factory[0], '::')) {
  1757.                     $factory[0] = substr($factory[0], 0$i);
  1758.                 }
  1759.                 $classes[] = trim($factory[0], '\\');
  1760.             }
  1761.             $definition $factory[0];
  1762.         }
  1763.         return array_filter($classes);
  1764.     }
  1765. }