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

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