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