Yaffs site version 1.1
[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\Variable;
15 use Symfony\Component\DependencyInjection\Definition;
16 use Symfony\Component\DependencyInjection\ContainerBuilder;
17 use Symfony\Component\DependencyInjection\Container;
18 use Symfony\Component\DependencyInjection\ContainerInterface;
19 use Symfony\Component\DependencyInjection\Reference;
20 use Symfony\Component\DependencyInjection\Parameter;
21 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
22 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
23 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
24 use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
25 use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
26 use Symfony\Component\DependencyInjection\ExpressionLanguage;
27 use Symfony\Component\ExpressionLanguage\Expression;
28 use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
29 use Symfony\Component\HttpKernel\Kernel;
30
31 /**
32  * PhpDumper dumps a service container as a PHP class.
33  *
34  * @author Fabien Potencier <fabien@symfony.com>
35  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
36  */
37 class PhpDumper extends Dumper
38 {
39     /**
40      * Characters that might appear in the generated variable name as first character.
41      *
42      * @var string
43      */
44     const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz';
45
46     /**
47      * Characters that might appear in the generated variable name as any but the first character.
48      *
49      * @var string
50      */
51     const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_';
52
53     private $inlinedDefinitions;
54     private $definitionVariables;
55     private $referenceVariables;
56     private $variableCount;
57     private $reservedVariables = array('instance', 'class');
58     private $expressionLanguage;
59     private $targetDirRegex;
60     private $targetDirMaxMatches;
61     private $docStar;
62
63     /**
64      * @var ExpressionFunctionProviderInterface[]
65      */
66     private $expressionLanguageProviders = array();
67
68     /**
69      * @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
70      */
71     private $proxyDumper;
72
73     /**
74      * {@inheritdoc}
75      */
76     public function __construct(ContainerBuilder $container)
77     {
78         parent::__construct($container);
79
80         $this->inlinedDefinitions = new \SplObjectStorage();
81     }
82
83     /**
84      * Sets the dumper to be used when dumping proxies in the generated container.
85      *
86      * @param ProxyDumper $proxyDumper
87      */
88     public function setProxyDumper(ProxyDumper $proxyDumper)
89     {
90         $this->proxyDumper = $proxyDumper;
91     }
92
93     /**
94      * Dumps the service container as a PHP class.
95      *
96      * Available options:
97      *
98      *  * class:      The class name
99      *  * base_class: The base class name
100      *  * namespace:  The class namespace
101      *
102      * @param array $options An array of options
103      *
104      * @return string A PHP class representing of the service container
105      */
106     public function dump(array $options = array())
107     {
108         $this->targetDirRegex = null;
109         $options = array_merge(array(
110             'class' => 'ProjectServiceContainer',
111             'base_class' => 'Container',
112             'namespace' => '',
113             'debug' => true,
114         ), $options);
115         $this->docStar = $options['debug'] ? '*' : '';
116
117         if (!empty($options['file']) && is_dir($dir = dirname($options['file']))) {
118             // Build a regexp where the first root dirs are mandatory,
119             // but every other sub-dir is optional up to the full path in $dir
120             // Mandate at least 2 root dirs and not more that 5 optional dirs.
121
122             $dir = explode(DIRECTORY_SEPARATOR, realpath($dir));
123             $i = count($dir);
124
125             if (3 <= $i) {
126                 $regex = '';
127                 $lastOptionalDir = $i > 8 ? $i - 5 : 3;
128                 $this->targetDirMaxMatches = $i - $lastOptionalDir;
129
130                 while (--$i >= $lastOptionalDir) {
131                     $regex = sprintf('(%s%s)?', preg_quote(DIRECTORY_SEPARATOR.$dir[$i], '#'), $regex);
132                 }
133
134                 do {
135                     $regex = preg_quote(DIRECTORY_SEPARATOR.$dir[$i], '#').$regex;
136                 } while (0 < --$i);
137
138                 $this->targetDirRegex = '#'.preg_quote($dir[0], '#').$regex.'#';
139             }
140         }
141
142         $code = $this->startClass($options['class'], $options['base_class'], $options['namespace']);
143
144         if ($this->container->isFrozen()) {
145             $code .= $this->addFrozenConstructor();
146             $code .= $this->addFrozenCompile();
147             $code .= $this->addIsFrozenMethod();
148         } else {
149             $code .= $this->addConstructor();
150         }
151
152         $code .=
153             $this->addServices().
154             $this->addDefaultParametersMethod().
155             $this->endClass().
156             $this->addProxyClasses()
157         ;
158         $this->targetDirRegex = null;
159
160         return $code;
161     }
162
163     /**
164      * Retrieves the currently set proxy dumper or instantiates one.
165      *
166      * @return ProxyDumper
167      */
168     private function getProxyDumper()
169     {
170         if (!$this->proxyDumper) {
171             $this->proxyDumper = new NullDumper();
172         }
173
174         return $this->proxyDumper;
175     }
176
177     /**
178      * Generates Service local temp variables.
179      *
180      * @param string $cId
181      * @param string $definition
182      *
183      * @return string
184      */
185     private function addServiceLocalTempVariables($cId, $definition)
186     {
187         static $template = "        \$%s = %s;\n";
188
189         $localDefinitions = array_merge(
190             array($definition),
191             $this->getInlinedDefinitions($definition)
192         );
193
194         $calls = $behavior = array();
195         foreach ($localDefinitions as $iDefinition) {
196             $this->getServiceCallsFromArguments($iDefinition->getArguments(), $calls, $behavior);
197             $this->getServiceCallsFromArguments($iDefinition->getMethodCalls(), $calls, $behavior);
198             $this->getServiceCallsFromArguments($iDefinition->getProperties(), $calls, $behavior);
199             $this->getServiceCallsFromArguments(array($iDefinition->getConfigurator()), $calls, $behavior);
200             $this->getServiceCallsFromArguments(array($iDefinition->getFactory()), $calls, $behavior);
201         }
202
203         $code = '';
204         foreach ($calls as $id => $callCount) {
205             if ('service_container' === $id || $id === $cId) {
206                 continue;
207             }
208
209             if ($callCount > 1) {
210                 $name = $this->getNextVariableName();
211                 $this->referenceVariables[$id] = new Variable($name);
212
213                 if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id]) {
214                     $code .= sprintf($template, $name, $this->getServiceCall($id));
215                 } else {
216                     $code .= sprintf($template, $name, $this->getServiceCall($id, new Reference($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)));
217                 }
218             }
219         }
220
221         if ('' !== $code) {
222             $code .= "\n";
223         }
224
225         return $code;
226     }
227
228     /**
229      * Generates code for the proxies to be attached after the container class.
230      *
231      * @return string
232      */
233     private function addProxyClasses()
234     {
235         /* @var $definitions Definition[] */
236         $definitions = array_filter(
237             $this->container->getDefinitions(),
238             array($this->getProxyDumper(), 'isProxyCandidate')
239         );
240         $code = '';
241         $strip = '' === $this->docStar && method_exists('Symfony\Component\HttpKernel\Kernel', 'stripComments');
242
243         foreach ($definitions as $definition) {
244             $proxyCode = "\n".$this->getProxyDumper()->getProxyCode($definition);
245             if ($strip) {
246                 $proxyCode = "<?php\n".$proxyCode;
247                 $proxyCode = substr(Kernel::stripComments($proxyCode), 5);
248             }
249             $code .= $proxyCode;
250         }
251
252         return $code;
253     }
254
255     /**
256      * Generates the require_once statement for service includes.
257      *
258      * @param string     $id         The service id
259      * @param Definition $definition
260      *
261      * @return string
262      */
263     private function addServiceInclude($id, $definition)
264     {
265         $template = "        require_once %s;\n";
266         $code = '';
267
268         if (null !== $file = $definition->getFile()) {
269             $code .= sprintf($template, $this->dumpValue($file));
270         }
271
272         foreach ($this->getInlinedDefinitions($definition) as $definition) {
273             if (null !== $file = $definition->getFile()) {
274                 $code .= sprintf($template, $this->dumpValue($file));
275             }
276         }
277
278         if ('' !== $code) {
279             $code .= "\n";
280         }
281
282         return $code;
283     }
284
285     /**
286      * Generates the inline definition of a service.
287      *
288      * @param string     $id
289      * @param Definition $definition
290      *
291      * @return string
292      *
293      * @throws RuntimeException                  When the factory definition is incomplete
294      * @throws ServiceCircularReferenceException When a circular reference is detected
295      */
296     private function addServiceInlinedDefinitions($id, $definition)
297     {
298         $code = '';
299         $variableMap = $this->definitionVariables;
300         $nbOccurrences = new \SplObjectStorage();
301         $processed = new \SplObjectStorage();
302         $inlinedDefinitions = $this->getInlinedDefinitions($definition);
303
304         foreach ($inlinedDefinitions as $definition) {
305             if (false === $nbOccurrences->contains($definition)) {
306                 $nbOccurrences->offsetSet($definition, 1);
307             } else {
308                 $i = $nbOccurrences->offsetGet($definition);
309                 $nbOccurrences->offsetSet($definition, $i + 1);
310             }
311         }
312
313         foreach ($inlinedDefinitions as $sDefinition) {
314             if ($processed->contains($sDefinition)) {
315                 continue;
316             }
317             $processed->offsetSet($sDefinition);
318
319             $class = $this->dumpValue($sDefinition->getClass());
320             if ($nbOccurrences->offsetGet($sDefinition) > 1 || $sDefinition->getMethodCalls() || $sDefinition->getProperties() || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) {
321                 $name = $this->getNextVariableName();
322                 $variableMap->offsetSet($sDefinition, new Variable($name));
323
324                 // a construct like:
325                 // $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a);
326                 // this is an indication for a wrong implementation, you can circumvent this problem
327                 // by setting up your service structure like this:
328                 // $b = new ServiceB();
329                 // $a = new ServiceA(ServiceB $b);
330                 // $b->setServiceA(ServiceA $a);
331                 if ($this->hasReference($id, $sDefinition->getArguments())) {
332                     throw new ServiceCircularReferenceException($id, array($id));
333                 }
334
335                 $code .= $this->addNewInstance($id, $sDefinition, '$'.$name, ' = ');
336
337                 if (!$this->hasReference($id, $sDefinition->getMethodCalls(), true) && !$this->hasReference($id, $sDefinition->getProperties(), true)) {
338                     $code .= $this->addServiceProperties(null, $sDefinition, $name);
339                     $code .= $this->addServiceMethodCalls(null, $sDefinition, $name);
340                     $code .= $this->addServiceConfigurator(null, $sDefinition, $name);
341                 }
342
343                 $code .= "\n";
344             }
345         }
346
347         return $code;
348     }
349
350     /**
351      * Adds the service return statement.
352      *
353      * @param string     $id         Service id
354      * @param Definition $definition
355      *
356      * @return string
357      */
358     private function addServiceReturn($id, $definition)
359     {
360         if ($this->isSimpleInstance($id, $definition)) {
361             return "    }\n";
362         }
363
364         return "\n        return \$instance;\n    }\n";
365     }
366
367     /**
368      * Generates the service instance.
369      *
370      * @param string     $id
371      * @param Definition $definition
372      *
373      * @return string
374      *
375      * @throws InvalidArgumentException
376      * @throws RuntimeException
377      */
378     private function addServiceInstance($id, Definition $definition)
379     {
380         $class = $definition->getClass();
381
382         if ('\\' === substr($class, 0, 1)) {
383             $class = substr($class, 1);
384         }
385
386         $class = $this->dumpValue($class);
387
388         if (0 === strpos($class, "'") && !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
389             throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
390         }
391
392         $simple = $this->isSimpleInstance($id, $definition);
393         $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
394         $instantiation = '';
395
396         if (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_CONTAINER === $definition->getScope(false)) {
397             $instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
398         } elseif (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
399             $instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
400         } elseif (!$simple) {
401             $instantiation = '$instance';
402         }
403
404         $return = '';
405         if ($simple) {
406             $return = 'return ';
407         } else {
408             $instantiation .= ' = ';
409         }
410
411         $code = $this->addNewInstance($id, $definition, $return, $instantiation);
412
413         if (!$simple) {
414             $code .= "\n";
415         }
416
417         return $code;
418     }
419
420     /**
421      * Checks if the definition is a simple instance.
422      *
423      * @param string     $id
424      * @param Definition $definition
425      *
426      * @return bool
427      */
428     private function isSimpleInstance($id, Definition $definition)
429     {
430         foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) {
431             if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) {
432                 continue;
433             }
434
435             if ($sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator()) {
436                 return false;
437             }
438         }
439
440         return true;
441     }
442
443     /**
444      * Adds method calls to a service definition.
445      *
446      * @param string     $id
447      * @param Definition $definition
448      * @param string     $variableName
449      *
450      * @return string
451      */
452     private function addServiceMethodCalls($id, Definition $definition, $variableName = 'instance')
453     {
454         $calls = '';
455         foreach ($definition->getMethodCalls() as $call) {
456             $arguments = array();
457             foreach ($call[1] as $value) {
458                 $arguments[] = $this->dumpValue($value);
459             }
460
461             $calls .= $this->wrapServiceConditionals($call[1], sprintf("        \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments)));
462         }
463
464         return $calls;
465     }
466
467     private function addServiceProperties($id, Definition $definition, $variableName = 'instance')
468     {
469         $code = '';
470         foreach ($definition->getProperties() as $name => $value) {
471             $code .= sprintf("        \$%s->%s = %s;\n", $variableName, $name, $this->dumpValue($value));
472         }
473
474         return $code;
475     }
476
477     /**
478      * Generates the inline definition setup.
479      *
480      * @param string     $id
481      * @param Definition $definition
482      *
483      * @return string
484      *
485      * @throws ServiceCircularReferenceException when the container contains a circular reference
486      */
487     private function addServiceInlinedDefinitionsSetup($id, Definition $definition)
488     {
489         $this->referenceVariables[$id] = new Variable('instance');
490
491         $code = '';
492         $processed = new \SplObjectStorage();
493         foreach ($this->getInlinedDefinitions($definition) as $iDefinition) {
494             if ($processed->contains($iDefinition)) {
495                 continue;
496             }
497             $processed->offsetSet($iDefinition);
498
499             if (!$this->hasReference($id, $iDefinition->getMethodCalls(), true) && !$this->hasReference($id, $iDefinition->getProperties(), true)) {
500                 continue;
501             }
502
503             // if the instance is simple, the return statement has already been generated
504             // so, the only possible way to get there is because of a circular reference
505             if ($this->isSimpleInstance($id, $definition)) {
506                 throw new ServiceCircularReferenceException($id, array($id));
507             }
508
509             $name = (string) $this->definitionVariables->offsetGet($iDefinition);
510             $code .= $this->addServiceProperties(null, $iDefinition, $name);
511             $code .= $this->addServiceMethodCalls(null, $iDefinition, $name);
512             $code .= $this->addServiceConfigurator(null, $iDefinition, $name);
513         }
514
515         if ('' !== $code) {
516             $code .= "\n";
517         }
518
519         return $code;
520     }
521
522     /**
523      * Adds configurator definition.
524      *
525      * @param string     $id
526      * @param Definition $definition
527      * @param string     $variableName
528      *
529      * @return string
530      */
531     private function addServiceConfigurator($id, Definition $definition, $variableName = 'instance')
532     {
533         if (!$callable = $definition->getConfigurator()) {
534             return '';
535         }
536
537         if (is_array($callable)) {
538             if ($callable[0] instanceof Reference
539                 || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
540                 return sprintf("        %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
541             }
542
543             $class = $this->dumpValue($callable[0]);
544             // If the class is a string we can optimize call_user_func away
545             if (strpos($class, "'") === 0) {
546                 return sprintf("        %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $callable[1], $variableName);
547             }
548
549             return sprintf("        call_user_func(array(%s, '%s'), \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
550         }
551
552         return sprintf("        %s(\$%s);\n", $callable, $variableName);
553     }
554
555     /**
556      * Adds a service.
557      *
558      * @param string     $id
559      * @param Definition $definition
560      *
561      * @return string
562      */
563     private function addService($id, Definition $definition)
564     {
565         $this->definitionVariables = new \SplObjectStorage();
566         $this->referenceVariables = array();
567         $this->variableCount = 0;
568
569         $return = array();
570
571         if ($definition->isSynthetic()) {
572             $return[] = '@throws RuntimeException always since this service is expected to be injected dynamically';
573         } elseif ($class = $definition->getClass()) {
574             $return[] = sprintf('@return %s A %s instance', 0 === strpos($class, '%') ? 'object' : '\\'.ltrim($class, '\\'), ltrim($class, '\\'));
575         } elseif ($definition->getFactory()) {
576             $factory = $definition->getFactory();
577             if (is_string($factory)) {
578                 $return[] = sprintf('@return object An instance returned by %s()', $factory);
579             } elseif (is_array($factory) && (is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) {
580                 if (is_string($factory[0]) || $factory[0] instanceof Reference) {
581                     $return[] = sprintf('@return object An instance returned by %s::%s()', (string) $factory[0], $factory[1]);
582                 } elseif ($factory[0] instanceof Definition) {
583                     $return[] = sprintf('@return object An instance returned by %s::%s()', $factory[0]->getClass(), $factory[1]);
584                 }
585             }
586         } elseif ($definition->getFactoryClass(false)) {
587             $return[] = sprintf('@return object An instance returned by %s::%s()', $definition->getFactoryClass(false), $definition->getFactoryMethod(false));
588         } elseif ($definition->getFactoryService(false)) {
589             $return[] = sprintf('@return object An instance returned by %s::%s()', $definition->getFactoryService(false), $definition->getFactoryMethod(false));
590         }
591
592         $scope = $definition->getScope(false);
593         if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
594             if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
595                 $return[] = '';
596             }
597             $return[] = sprintf("@throws InactiveScopeException when the '%s' service is requested while the '%s' scope is not active", $id, $scope);
598         }
599
600         if ($definition->isDeprecated()) {
601             if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
602                 $return[] = '';
603             }
604
605             $return[] = sprintf('@deprecated %s', $definition->getDeprecationMessage($id));
606         }
607
608         $return = str_replace("\n     * \n", "\n     *\n", implode("\n     * ", $return));
609
610         $doc = '';
611         if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
612             $doc .= <<<'EOF'
613
614      *
615      * This service is shared.
616      * This method always returns the same instance of the service.
617 EOF;
618         }
619
620         if (!$definition->isPublic()) {
621             $doc .= <<<'EOF'
622
623      *
624      * This service is private.
625      * If you want to be able to request this service from the container directly,
626      * make it public, otherwise you might end up with broken code.
627 EOF;
628         }
629
630         if ($definition->isAutowired()) {
631             $doc .= <<<EOF
632
633      *
634      * This service is autowired.
635 EOF;
636         }
637
638         if ($definition->isLazy()) {
639             $lazyInitialization = '$lazyLoad = true';
640             $lazyInitializationDoc = "\n     * @param bool    \$lazyLoad whether to try lazy-loading the service with a proxy\n     *";
641         } else {
642             $lazyInitialization = '';
643             $lazyInitializationDoc = '';
644         }
645
646         // with proxies, for 5.3.3 compatibility, the getter must be public to be accessible to the initializer
647         $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
648         $visibility = $isProxyCandidate ? 'public' : 'protected';
649         $code = <<<EOF
650
651     /*{$this->docStar}
652      * Gets the '$id' service.$doc
653      *$lazyInitializationDoc
654      * $return
655      */
656     {$visibility} function get{$this->camelize($id)}Service($lazyInitialization)
657     {
658
659 EOF;
660
661         $code .= $isProxyCandidate ? $this->getProxyDumper()->getProxyFactoryCode($definition, $id) : '';
662
663         if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
664             $code .= <<<EOF
665         if (!isset(\$this->scopedServices['$scope'])) {
666             throw new InactiveScopeException('$id', '$scope');
667         }
668
669
670 EOF;
671         }
672
673         if ($definition->isSynthetic()) {
674             $code .= sprintf("        throw new RuntimeException('You have requested a synthetic service (\"%s\"). The DIC does not know how to construct this service.');\n    }\n", $id);
675         } else {
676             if ($definition->isDeprecated()) {
677                 $code .= sprintf("        @trigger_error(%s, E_USER_DEPRECATED);\n\n", var_export($definition->getDeprecationMessage($id), true));
678             }
679
680             $code .=
681                 $this->addServiceInclude($id, $definition).
682                 $this->addServiceLocalTempVariables($id, $definition).
683                 $this->addServiceInlinedDefinitions($id, $definition).
684                 $this->addServiceInstance($id, $definition).
685                 $this->addServiceInlinedDefinitionsSetup($id, $definition).
686                 $this->addServiceProperties($id, $definition).
687                 $this->addServiceMethodCalls($id, $definition).
688                 $this->addServiceConfigurator($id, $definition).
689                 $this->addServiceReturn($id, $definition)
690             ;
691         }
692
693         $this->definitionVariables = null;
694         $this->referenceVariables = null;
695
696         return $code;
697     }
698
699     /**
700      * Adds multiple services.
701      *
702      * @return string
703      */
704     private function addServices()
705     {
706         $publicServices = $privateServices = $synchronizers = '';
707         $definitions = $this->container->getDefinitions();
708         ksort($definitions);
709         foreach ($definitions as $id => $definition) {
710             if ($definition->isPublic()) {
711                 $publicServices .= $this->addService($id, $definition);
712             } else {
713                 $privateServices .= $this->addService($id, $definition);
714             }
715
716             $synchronizers .= $this->addServiceSynchronizer($id, $definition);
717         }
718
719         return $publicServices.$synchronizers.$privateServices;
720     }
721
722     /**
723      * Adds synchronizer methods.
724      *
725      * @param string     $id         A service identifier
726      * @param Definition $definition A Definition instance
727      *
728      * @return string|null
729      *
730      * @deprecated since version 2.7, will be removed in 3.0.
731      */
732     private function addServiceSynchronizer($id, Definition $definition)
733     {
734         if (!$definition->isSynchronized(false)) {
735             return;
736         }
737
738         if ('request' !== $id) {
739             @trigger_error('Synchronized services were deprecated in version 2.7 and won\'t work anymore in 3.0.', E_USER_DEPRECATED);
740         }
741
742         $code = '';
743         foreach ($this->container->getDefinitions() as $definitionId => $definition) {
744             foreach ($definition->getMethodCalls() as $call) {
745                 foreach ($call[1] as $argument) {
746                     if ($argument instanceof Reference && $id == (string) $argument) {
747                         $arguments = array();
748                         foreach ($call[1] as $value) {
749                             $arguments[] = $this->dumpValue($value);
750                         }
751
752                         $call = $this->wrapServiceConditionals($call[1], sprintf("\$this->get('%s')->%s(%s);", $definitionId, $call[0], implode(', ', $arguments)));
753
754                         $code .= <<<EOF
755         if (\$this->initialized('$definitionId')) {
756             $call
757         }
758
759 EOF;
760                     }
761                 }
762             }
763         }
764
765         if (!$code) {
766             return;
767         }
768
769         return <<<EOF
770
771     /*{$this->docStar}
772      * Updates the '$id' service.
773      */
774     protected function synchronize{$this->camelize($id)}Service()
775     {
776 $code    }
777
778 EOF;
779     }
780
781     private function addNewInstance($id, Definition $definition, $return, $instantiation)
782     {
783         $class = $this->dumpValue($definition->getClass());
784
785         $arguments = array();
786         foreach ($definition->getArguments() as $value) {
787             $arguments[] = $this->dumpValue($value);
788         }
789
790         if (null !== $definition->getFactory()) {
791             $callable = $definition->getFactory();
792             if (is_array($callable)) {
793                 if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) {
794                     throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $callable[1] ?: 'n/a'));
795                 }
796
797                 if ($callable[0] instanceof Reference
798                     || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
799                     return sprintf("        $return{$instantiation}%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '');
800                 }
801
802                 $class = $this->dumpValue($callable[0]);
803                 // If the class is a string we can optimize call_user_func away
804                 if (strpos($class, "'") === 0) {
805                     return sprintf("        $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '');
806                 }
807
808                 return sprintf("        $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : '');
809             }
810
811             return sprintf("        $return{$instantiation}\\%s(%s);\n", $callable, $arguments ? implode(', ', $arguments) : '');
812         } elseif (null !== $definition->getFactoryMethod(false)) {
813             if (null !== $definition->getFactoryClass(false)) {
814                 $class = $this->dumpValue($definition->getFactoryClass(false));
815
816                 // If the class is a string we can optimize call_user_func away
817                 if (strpos($class, "'") === 0) {
818                     return sprintf("        $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $definition->getFactoryMethod(false), $arguments ? implode(', ', $arguments) : '');
819                 }
820
821                 return sprintf("        $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass(false)), $definition->getFactoryMethod(false), $arguments ? ', '.implode(', ', $arguments) : '');
822             }
823
824             if (null !== $definition->getFactoryService(false)) {
825                 return sprintf("        $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService(false)), $definition->getFactoryMethod(false), implode(', ', $arguments));
826             }
827
828             throw new RuntimeException(sprintf('Factory method requires a factory service or factory class in service definition for %s', $id));
829         }
830
831         if (false !== strpos($class, '$')) {
832             return sprintf("        \$class = %s;\n\n        $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments));
833         }
834
835         return sprintf("        $return{$instantiation}new %s(%s);\n", $this->dumpLiteralClass($class), implode(', ', $arguments));
836     }
837
838     /**
839      * Adds the class headers.
840      *
841      * @param string $class     Class name
842      * @param string $baseClass The name of the base class
843      * @param string $namespace The class namespace
844      *
845      * @return string
846      */
847     private function startClass($class, $baseClass, $namespace)
848     {
849         $bagClass = $this->container->isFrozen() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;';
850         $namespaceLine = $namespace ? "\nnamespace $namespace;\n" : '';
851
852         return <<<EOF
853 <?php
854 $namespaceLine
855 use Symfony\Component\DependencyInjection\ContainerInterface;
856 use Symfony\Component\DependencyInjection\Container;
857 use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
858 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
859 use Symfony\Component\DependencyInjection\Exception\LogicException;
860 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
861 $bagClass
862
863 /*{$this->docStar}
864  * $class.
865  *
866  * This class has been auto-generated
867  * by the Symfony Dependency Injection Component.
868  */
869 class $class extends $baseClass
870 {
871     private \$parameters;
872     private \$targetDirs = array();
873
874 EOF;
875     }
876
877     /**
878      * Adds the constructor.
879      *
880      * @return string
881      */
882     private function addConstructor()
883     {
884         $targetDirs = $this->exportTargetDirs();
885         $arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null;
886
887         $code = <<<EOF
888
889     /*{$this->docStar}
890      * Constructor.
891      */
892     public function __construct()
893     {{$targetDirs}
894         parent::__construct($arguments);
895
896 EOF;
897
898         if (count($scopes = $this->container->getScopes(false)) > 0) {
899             $code .= "\n";
900             $code .= '        $this->scopes = '.$this->dumpValue($scopes).";\n";
901             $code .= '        $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
902         }
903
904         $code .= $this->addMethodMap();
905         $code .= $this->addAliases();
906
907         $code .= <<<'EOF'
908     }
909
910 EOF;
911
912         return $code;
913     }
914
915     /**
916      * Adds the constructor for a frozen container.
917      *
918      * @return string
919      */
920     private function addFrozenConstructor()
921     {
922         $targetDirs = $this->exportTargetDirs();
923
924         $code = <<<EOF
925
926     /*{$this->docStar}
927      * Constructor.
928      */
929     public function __construct()
930     {{$targetDirs}
931 EOF;
932
933         if ($this->container->getParameterBag()->all()) {
934             $code .= "\n        \$this->parameters = \$this->getDefaultParameters();\n";
935         }
936
937         $code .= <<<'EOF'
938
939         $this->services =
940         $this->scopedServices =
941         $this->scopeStacks = array();
942 EOF;
943
944         $code .= "\n";
945         if (count($scopes = $this->container->getScopes(false)) > 0) {
946             $code .= '        $this->scopes = '.$this->dumpValue($scopes).";\n";
947             $code .= '        $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
948         } else {
949             $code .= "        \$this->scopes = array();\n";
950             $code .= "        \$this->scopeChildren = array();\n";
951         }
952
953         $code .= $this->addMethodMap();
954         $code .= $this->addAliases();
955
956         $code .= <<<'EOF'
957     }
958
959 EOF;
960
961         return $code;
962     }
963
964     /**
965      * Adds the constructor for a frozen container.
966      *
967      * @return string
968      */
969     private function addFrozenCompile()
970     {
971         return <<<EOF
972
973     /*{$this->docStar}
974      * {@inheritdoc}
975      */
976     public function compile()
977     {
978         throw new LogicException('You cannot compile a dumped frozen container.');
979     }
980
981 EOF;
982     }
983
984     /**
985      * Adds the isFrozen method for a frozen container.
986      *
987      * @return string
988      */
989     private function addIsFrozenMethod()
990     {
991         return <<<EOF
992
993     /*{$this->docStar}
994      * {@inheritdoc}
995      */
996     public function isFrozen()
997     {
998         return true;
999     }
1000
1001 EOF;
1002     }
1003
1004     /**
1005      * Adds the methodMap property definition.
1006      *
1007      * @return string
1008      */
1009     private function addMethodMap()
1010     {
1011         if (!$definitions = $this->container->getDefinitions()) {
1012             return '';
1013         }
1014
1015         $code = "        \$this->methodMap = array(\n";
1016         ksort($definitions);
1017         foreach ($definitions as $id => $definition) {
1018             $code .= '            '.var_export($id, true).' => '.var_export('get'.$this->camelize($id).'Service', true).",\n";
1019         }
1020
1021         return $code."        );\n";
1022     }
1023
1024     /**
1025      * Adds the aliases property definition.
1026      *
1027      * @return string
1028      */
1029     private function addAliases()
1030     {
1031         if (!$aliases = $this->container->getAliases()) {
1032             return $this->container->isFrozen() ? "\n        \$this->aliases = array();\n" : '';
1033         }
1034
1035         $code = "        \$this->aliases = array(\n";
1036         ksort($aliases);
1037         foreach ($aliases as $alias => $id) {
1038             $id = (string) $id;
1039             while (isset($aliases[$id])) {
1040                 $id = (string) $aliases[$id];
1041             }
1042             $code .= '            '.var_export($alias, true).' => '.var_export($id, true).",\n";
1043         }
1044
1045         return $code."        );\n";
1046     }
1047
1048     /**
1049      * Adds default parameters method.
1050      *
1051      * @return string
1052      */
1053     private function addDefaultParametersMethod()
1054     {
1055         if (!$this->container->getParameterBag()->all()) {
1056             return '';
1057         }
1058
1059         $parameters = $this->exportParameters($this->container->getParameterBag()->all());
1060
1061         $code = '';
1062         if ($this->container->isFrozen()) {
1063             $code .= <<<'EOF'
1064
1065     /**
1066      * {@inheritdoc}
1067      */
1068     public function getParameter($name)
1069     {
1070         $name = strtolower($name);
1071
1072         if (!(isset($this->parameters[$name]) || array_key_exists($name, $this->parameters))) {
1073             throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
1074         }
1075
1076         return $this->parameters[$name];
1077     }
1078
1079     /**
1080      * {@inheritdoc}
1081      */
1082     public function hasParameter($name)
1083     {
1084         $name = strtolower($name);
1085
1086         return isset($this->parameters[$name]) || array_key_exists($name, $this->parameters);
1087     }
1088
1089     /**
1090      * {@inheritdoc}
1091      */
1092     public function setParameter($name, $value)
1093     {
1094         throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
1095     }
1096
1097     /**
1098      * {@inheritdoc}
1099      */
1100     public function getParameterBag()
1101     {
1102         if (null === $this->parameterBag) {
1103             $this->parameterBag = new FrozenParameterBag($this->parameters);
1104         }
1105
1106         return $this->parameterBag;
1107     }
1108
1109 EOF;
1110             if ('' === $this->docStar) {
1111                 $code = str_replace('/**', '/*', $code);
1112             }
1113         }
1114
1115         $code .= <<<EOF
1116
1117     /*{$this->docStar}
1118      * Gets the default parameters.
1119      *
1120      * @return array An array of the default parameters
1121      */
1122     protected function getDefaultParameters()
1123     {
1124         return $parameters;
1125     }
1126
1127 EOF;
1128
1129         return $code;
1130     }
1131
1132     /**
1133      * Exports parameters.
1134      *
1135      * @param array  $parameters
1136      * @param string $path
1137      * @param int    $indent
1138      *
1139      * @return string
1140      *
1141      * @throws InvalidArgumentException
1142      */
1143     private function exportParameters(array $parameters, $path = '', $indent = 12)
1144     {
1145         $php = array();
1146         foreach ($parameters as $key => $value) {
1147             if (is_array($value)) {
1148                 $value = $this->exportParameters($value, $path.'/'.$key, $indent + 4);
1149             } elseif ($value instanceof Variable) {
1150                 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".', $value, $path.'/'.$key));
1151             } elseif ($value instanceof Definition) {
1152                 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));
1153             } elseif ($value instanceof Reference) {
1154                 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));
1155             } elseif ($value instanceof Expression) {
1156                 throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain expressions. Expression "%s" found in "%s".', $value, $path.'/'.$key));
1157             } else {
1158                 $value = $this->export($value);
1159             }
1160
1161             $php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), var_export($key, true), $value);
1162         }
1163
1164         return sprintf("array(\n%s\n%s)", implode("\n", $php), str_repeat(' ', $indent - 4));
1165     }
1166
1167     /**
1168      * Ends the class definition.
1169      *
1170      * @return string
1171      */
1172     private function endClass()
1173     {
1174         return <<<'EOF'
1175 }
1176
1177 EOF;
1178     }
1179
1180     /**
1181      * Wraps the service conditionals.
1182      *
1183      * @param string $value
1184      * @param string $code
1185      *
1186      * @return string
1187      */
1188     private function wrapServiceConditionals($value, $code)
1189     {
1190         if (!$services = ContainerBuilder::getServiceConditionals($value)) {
1191             return $code;
1192         }
1193
1194         $conditions = array();
1195         foreach ($services as $service) {
1196             $conditions[] = sprintf("\$this->has('%s')", $service);
1197         }
1198
1199         // re-indent the wrapped code
1200         $code = implode("\n", array_map(function ($line) { return $line ? '    '.$line : $line; }, explode("\n", $code)));
1201
1202         return sprintf("        if (%s) {\n%s        }\n", implode(' && ', $conditions), $code);
1203     }
1204
1205     /**
1206      * Builds service calls from arguments.
1207      *
1208      * @param array $arguments
1209      * @param array &$calls    By reference
1210      * @param array &$behavior By reference
1211      */
1212     private function getServiceCallsFromArguments(array $arguments, array &$calls, array &$behavior)
1213     {
1214         foreach ($arguments as $argument) {
1215             if (is_array($argument)) {
1216                 $this->getServiceCallsFromArguments($argument, $calls, $behavior);
1217             } elseif ($argument instanceof Reference) {
1218                 $id = (string) $argument;
1219
1220                 if (!isset($calls[$id])) {
1221                     $calls[$id] = 0;
1222                 }
1223                 if (!isset($behavior[$id])) {
1224                     $behavior[$id] = $argument->getInvalidBehavior();
1225                 } elseif (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $behavior[$id]) {
1226                     $behavior[$id] = $argument->getInvalidBehavior();
1227                 }
1228
1229                 ++$calls[$id];
1230             }
1231         }
1232     }
1233
1234     /**
1235      * Returns the inline definition.
1236      *
1237      * @param Definition $definition
1238      *
1239      * @return array
1240      */
1241     private function getInlinedDefinitions(Definition $definition)
1242     {
1243         if (false === $this->inlinedDefinitions->contains($definition)) {
1244             $definitions = array_merge(
1245                 $this->getDefinitionsFromArguments($definition->getArguments()),
1246                 $this->getDefinitionsFromArguments($definition->getMethodCalls()),
1247                 $this->getDefinitionsFromArguments($definition->getProperties()),
1248                 $this->getDefinitionsFromArguments(array($definition->getConfigurator())),
1249                 $this->getDefinitionsFromArguments(array($definition->getFactory()))
1250             );
1251
1252             $this->inlinedDefinitions->offsetSet($definition, $definitions);
1253
1254             return $definitions;
1255         }
1256
1257         return $this->inlinedDefinitions->offsetGet($definition);
1258     }
1259
1260     /**
1261      * Gets the definition from arguments.
1262      *
1263      * @param array $arguments
1264      *
1265      * @return array
1266      */
1267     private function getDefinitionsFromArguments(array $arguments)
1268     {
1269         $definitions = array();
1270         foreach ($arguments as $argument) {
1271             if (is_array($argument)) {
1272                 $definitions = array_merge($definitions, $this->getDefinitionsFromArguments($argument));
1273             } elseif ($argument instanceof Definition) {
1274                 $definitions = array_merge(
1275                     $definitions,
1276                     $this->getInlinedDefinitions($argument),
1277                     array($argument)
1278                 );
1279             }
1280         }
1281
1282         return $definitions;
1283     }
1284
1285     /**
1286      * Checks if a service id has a reference.
1287      *
1288      * @param string $id
1289      * @param array  $arguments
1290      * @param bool   $deep
1291      * @param array  $visited
1292      *
1293      * @return bool
1294      */
1295     private function hasReference($id, array $arguments, $deep = false, array &$visited = array())
1296     {
1297         foreach ($arguments as $argument) {
1298             if (is_array($argument)) {
1299                 if ($this->hasReference($id, $argument, $deep, $visited)) {
1300                     return true;
1301                 }
1302             } elseif ($argument instanceof Reference) {
1303                 $argumentId = (string) $argument;
1304                 if ($id === $argumentId) {
1305                     return true;
1306                 }
1307
1308                 if ($deep && !isset($visited[$argumentId]) && 'service_container' !== $argumentId) {
1309                     $visited[$argumentId] = true;
1310
1311                     $service = $this->container->getDefinition($argumentId);
1312
1313                     // if the proxy manager is enabled, disable searching for references in lazy services,
1314                     // as these services will be instantiated lazily and don't have direct related references.
1315                     if ($service->isLazy() && !$this->getProxyDumper() instanceof NullDumper) {
1316                         continue;
1317                     }
1318
1319                     $arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());
1320
1321                     if ($this->hasReference($id, $arguments, $deep, $visited)) {
1322                         return true;
1323                     }
1324                 }
1325             }
1326         }
1327
1328         return false;
1329     }
1330
1331     /**
1332      * Dumps values.
1333      *
1334      * @param mixed $value
1335      * @param bool  $interpolate
1336      *
1337      * @return string
1338      *
1339      * @throws RuntimeException
1340      */
1341     private function dumpValue($value, $interpolate = true)
1342     {
1343         if (is_array($value)) {
1344             $code = array();
1345             foreach ($value as $k => $v) {
1346                 $code[] = sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
1347             }
1348
1349             return sprintf('array(%s)', implode(', ', $code));
1350         } elseif ($value instanceof Definition) {
1351             if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {
1352                 return $this->dumpValue($this->definitionVariables->offsetGet($value), $interpolate);
1353             }
1354             if ($value->getMethodCalls()) {
1355                 throw new RuntimeException('Cannot dump definitions which have method calls.');
1356             }
1357             if ($value->getProperties()) {
1358                 throw new RuntimeException('Cannot dump definitions which have properties.');
1359             }
1360             if (null !== $value->getConfigurator()) {
1361                 throw new RuntimeException('Cannot dump definitions which have a configurator.');
1362             }
1363
1364             $arguments = array();
1365             foreach ($value->getArguments() as $argument) {
1366                 $arguments[] = $this->dumpValue($argument);
1367             }
1368
1369             if (null !== $value->getFactory()) {
1370                 $factory = $value->getFactory();
1371
1372                 if (is_string($factory)) {
1373                     return sprintf('\\%s(%s)', $factory, implode(', ', $arguments));
1374                 }
1375
1376                 if (is_array($factory)) {
1377                     if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $factory[1])) {
1378                         throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $factory[1] ?: 'n/a'));
1379                     }
1380
1381                     if (is_string($factory[0])) {
1382                         return sprintf('%s::%s(%s)', $this->dumpLiteralClass($this->dumpValue($factory[0])), $factory[1], implode(', ', $arguments));
1383                     }
1384
1385                     if ($factory[0] instanceof Definition) {
1386                         return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($factory[0]), $factory[1], count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1387                     }
1388
1389                     if ($factory[0] instanceof Reference) {
1390                         return sprintf('%s->%s(%s)', $this->dumpValue($factory[0]), $factory[1], implode(', ', $arguments));
1391                     }
1392                 }
1393
1394                 throw new RuntimeException('Cannot dump definition because of invalid factory');
1395             }
1396
1397             if (null !== $value->getFactoryMethod(false)) {
1398                 if (null !== $value->getFactoryClass(false)) {
1399                     return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($value->getFactoryClass(false)), $value->getFactoryMethod(false), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
1400                 } elseif (null !== $value->getFactoryService(false)) {
1401                     $service = $this->dumpValue($value->getFactoryService(false));
1402
1403                     return sprintf('%s->%s(%s)', 0 === strpos($service, '$') ? sprintf('$this->get(%s)', $service) : $this->getServiceCall($value->getFactoryService(false)), $value->getFactoryMethod(false), implode(', ', $arguments));
1404                 }
1405
1406                 throw new RuntimeException('Cannot dump definitions which have factory method without factory service or factory class.');
1407             }
1408
1409             $class = $value->getClass();
1410             if (null === $class) {
1411                 throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
1412             }
1413
1414             return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments));
1415         } elseif ($value instanceof Variable) {
1416             return '$'.$value;
1417         } elseif ($value instanceof Reference) {
1418             if (null !== $this->referenceVariables && isset($this->referenceVariables[$id = (string) $value])) {
1419                 return $this->dumpValue($this->referenceVariables[$id], $interpolate);
1420             }
1421
1422             return $this->getServiceCall((string) $value, $value);
1423         } elseif ($value instanceof Expression) {
1424             return $this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
1425         } elseif ($value instanceof Parameter) {
1426             return $this->dumpParameter($value);
1427         } elseif (true === $interpolate && is_string($value)) {
1428             if (preg_match('/^%([^%]+)%$/', $value, $match)) {
1429                 // we do this to deal with non string values (Boolean, integer, ...)
1430                 // the preg_replace_callback converts them to strings
1431                 return $this->dumpParameter(strtolower($match[1]));
1432             } else {
1433                 $that = $this;
1434                 $replaceParameters = function ($match) use ($that) {
1435                     return "'.".$that->dumpParameter(strtolower($match[2])).".'";
1436                 };
1437
1438                 $code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, $this->export($value)));
1439
1440                 return $code;
1441             }
1442         } elseif (is_object($value) || is_resource($value)) {
1443             throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
1444         }
1445
1446         return $this->export($value);
1447     }
1448
1449     /**
1450      * Dumps a string to a literal (aka PHP Code) class value.
1451      *
1452      * @param string $class
1453      *
1454      * @return string
1455      *
1456      * @throws RuntimeException
1457      */
1458     private function dumpLiteralClass($class)
1459     {
1460         if (false !== strpos($class, '$')) {
1461             throw new RuntimeException('Cannot dump definitions which have a variable class name.');
1462         }
1463         if (0 !== strpos($class, "'") || !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
1464             throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s)', $class ?: 'n/a'));
1465         }
1466
1467         return '\\'.substr(str_replace('\\\\', '\\', $class), 1, -1);
1468     }
1469
1470     /**
1471      * Dumps a parameter.
1472      *
1473      * @param string $name
1474      *
1475      * @return string
1476      */
1477     public function dumpParameter($name)
1478     {
1479         if ($this->container->isFrozen() && $this->container->hasParameter($name)) {
1480             return $this->dumpValue($this->container->getParameter($name), false);
1481         }
1482
1483         return sprintf("\$this->getParameter('%s')", strtolower($name));
1484     }
1485
1486     /**
1487      * @deprecated since version 2.6.2, to be removed in 3.0.
1488      *             Use \Symfony\Component\DependencyInjection\ContainerBuilder::addExpressionLanguageProvider instead.
1489      *
1490      * @param ExpressionFunctionProviderInterface $provider
1491      */
1492     public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
1493     {
1494         @trigger_error('The '.__METHOD__.' method is deprecated since version 2.6.2 and will be removed in 3.0. Use the Symfony\Component\DependencyInjection\ContainerBuilder::addExpressionLanguageProvider method instead.', E_USER_DEPRECATED);
1495
1496         $this->expressionLanguageProviders[] = $provider;
1497     }
1498
1499     /**
1500      * Gets a service call.
1501      *
1502      * @param string    $id
1503      * @param Reference $reference
1504      *
1505      * @return string
1506      */
1507     private function getServiceCall($id, Reference $reference = null)
1508     {
1509         if ('service_container' === $id) {
1510             return '$this';
1511         }
1512
1513         if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
1514             return sprintf('$this->get(\'%s\', ContainerInterface::NULL_ON_INVALID_REFERENCE)', $id);
1515         }
1516
1517         if ($this->container->hasAlias($id)) {
1518             $id = (string) $this->container->getAlias($id);
1519         }
1520
1521         return sprintf('$this->get(\'%s\')', $id);
1522     }
1523
1524     /**
1525      * Convert a service id to a valid PHP method name.
1526      *
1527      * @param string $id
1528      *
1529      * @return string
1530      *
1531      * @throws InvalidArgumentException
1532      */
1533     private function camelize($id)
1534     {
1535         $name = Container::camelize($id);
1536
1537         if (!preg_match('/^[a-zA-Z0-9_\x7f-\xff]+$/', $name)) {
1538             throw new InvalidArgumentException(sprintf('Service id "%s" cannot be converted to a valid PHP method name.', $id));
1539         }
1540
1541         return $name;
1542     }
1543
1544     /**
1545      * Returns the next name to use.
1546      *
1547      * @return string
1548      */
1549     private function getNextVariableName()
1550     {
1551         $firstChars = self::FIRST_CHARS;
1552         $firstCharsLength = strlen($firstChars);
1553         $nonFirstChars = self::NON_FIRST_CHARS;
1554         $nonFirstCharsLength = strlen($nonFirstChars);
1555
1556         while (true) {
1557             $name = '';
1558             $i = $this->variableCount;
1559
1560             if ('' === $name) {
1561                 $name .= $firstChars[$i % $firstCharsLength];
1562                 $i = (int) ($i / $firstCharsLength);
1563             }
1564
1565             while ($i > 0) {
1566                 --$i;
1567                 $name .= $nonFirstChars[$i % $nonFirstCharsLength];
1568                 $i = (int) ($i / $nonFirstCharsLength);
1569             }
1570
1571             ++$this->variableCount;
1572
1573             // check that the name is not reserved
1574             if (in_array($name, $this->reservedVariables, true)) {
1575                 continue;
1576             }
1577
1578             return $name;
1579         }
1580     }
1581
1582     private function getExpressionLanguage()
1583     {
1584         if (null === $this->expressionLanguage) {
1585             if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
1586                 throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
1587             }
1588             $providers = array_merge($this->container->getExpressionLanguageProviders(), $this->expressionLanguageProviders);
1589             $this->expressionLanguage = new ExpressionLanguage(null, $providers);
1590
1591             if ($this->container->isTrackingResources()) {
1592                 foreach ($providers as $provider) {
1593                     $this->container->addObjectResource($provider);
1594                 }
1595             }
1596         }
1597
1598         return $this->expressionLanguage;
1599     }
1600
1601     private function exportTargetDirs()
1602     {
1603         return null === $this->targetDirRegex ? '' : <<<EOF
1604
1605         \$dir = __DIR__;
1606         for (\$i = 1; \$i <= {$this->targetDirMaxMatches}; ++\$i) {
1607             \$this->targetDirs[\$i] = \$dir = dirname(\$dir);
1608         }
1609 EOF;
1610     }
1611
1612     private function export($value)
1613     {
1614         if (null !== $this->targetDirRegex && is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) {
1615             $prefix = $matches[0][1] ? var_export(substr($value, 0, $matches[0][1]), true).'.' : '';
1616             $suffix = $matches[0][1] + strlen($matches[0][0]);
1617             $suffix = isset($value[$suffix]) ? '.'.var_export(substr($value, $suffix), true) : '';
1618             $dirname = '__DIR__';
1619
1620             if (0 < $offset = 1 + $this->targetDirMaxMatches - count($matches)) {
1621                 $dirname = sprintf('$this->targetDirs[%d]', $offset);
1622             }
1623
1624             if ($prefix || $suffix) {
1625                 return sprintf('(%s%s%s)', $prefix, $dirname, $suffix);
1626             }
1627
1628             return $dirname;
1629         }
1630
1631         return var_export($value, true);
1632     }
1633 }