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