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