function PhpDumper::dump
Dumps the service container as a PHP class.
Available options:
- class: The class name
- base_class: The base class name
- namespace: The class namespace
- as_files: To split the container in several files
Return value
string|array A PHP class representing the service container or an array of PHP files if the "as_files" option is set
Throws
EnvParameterException When an env var exists but has not been dumped
Overrides DumperInterface::dump
File
-
vendor/
symfony/ dependency-injection/ Dumper/ PhpDumper.php, line 131
Class
- PhpDumper
- PhpDumper dumps a service container as a PHP class.
Namespace
Symfony\Component\DependencyInjection\DumperCode
public function dump(array $options = []) : string|array {
$this->locatedIds = [];
$this->targetDirRegex = null;
$this->inlinedRequires = [];
$this->exportedVariables = [];
$this->dynamicParameters = [];
$options = array_merge([
'class' => 'ProjectServiceContainer',
'base_class' => 'Container',
'namespace' => '',
'as_files' => false,
'debug' => true,
'hot_path_tag' => 'container.hot_path',
'preload_tags' => [
'container.preload',
'container.no_preload',
],
'inline_factories' => null,
'inline_class_loader' => null,
'preload_classes' => [],
'service_locator_tag' => 'container.service_locator',
'build_time' => time(),
], $options);
$this->addGetService = false;
$this->namespace = $options['namespace'];
$this->asFiles = $options['as_files'];
$this->hotPathTag = $options['hot_path_tag'];
$this->preloadTags = $options['preload_tags'];
$this->inlineFactories = false;
if (isset($options['inline_factories'])) {
$this->inlineFactories = $this->asFiles && $options['inline_factories'];
}
$this->inlineRequires = $options['debug'];
if (isset($options['inline_class_loader'])) {
$this->inlineRequires = $options['inline_class_loader'];
}
$this->serviceLocatorTag = $options['service_locator_tag'];
$this->class = $options['class'];
if (!str_starts_with($baseClass = $options['base_class'], '\\') && 'Container' !== $baseClass) {
$baseClass = \sprintf('%s\\%s', $options['namespace'] ? '\\' . $options['namespace'] : '', $baseClass);
$this->baseClass = $baseClass;
}
elseif ('Container' === $baseClass) {
$this->baseClass = Container::class;
}
else {
$this->baseClass = $baseClass;
}
$this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass);
if (!$this->hasProxyDumper) {
(new AnalyzeServiceReferencesPass(true, false))->process($this->container);
(new CheckCircularReferencesPass())->process($this->container);
}
$this->analyzeReferences();
$this->docStar = $options['debug'] ? '*' : '';
if (!empty($options['file']) && is_dir($dir = \dirname($options['file']))) {
// Build a regexp where the first root dirs are mandatory,
// but every other sub-dir is optional up to the full path in $dir
// Mandate at least 1 root dir and not more than 5 optional dirs.
$dir = explode(\DIRECTORY_SEPARATOR, realpath($dir));
$i = \count($dir);
if (2 + (int) ('\\' === \DIRECTORY_SEPARATOR) <= $i) {
$regex = '';
$lastOptionalDir = $i > 8 ? $i - 5 : 2 + (int) ('\\' === \DIRECTORY_SEPARATOR);
$this->targetDirMaxMatches = $i - $lastOptionalDir;
while (--$i >= $lastOptionalDir) {
$regex = \sprintf('(%s%s)?', preg_quote(\DIRECTORY_SEPARATOR . $dir[$i], '#'), $regex);
}
do {
$regex = preg_quote(\DIRECTORY_SEPARATOR . $dir[$i], '#') . $regex;
} while (0 < --$i);
$this->targetDirRegex = '#(^|file://|[:;, \\|\\r\\n])' . preg_quote($dir[0], '#') . $regex . '#';
}
}
$proxyClasses = $this->inlineFactories ? $this->generateProxyClasses() : null;
if ($options['preload_classes']) {
$this->preload = array_combine($options['preload_classes'], $options['preload_classes']);
}
$code = $this->addDefaultParametersMethod();
$code = $this->startClass($options['class'], $baseClass, $this->inlineFactories && $proxyClasses) . $this->addServices($services) . $this->addDeprecatedAliases() . $code;
$proxyClasses ??= $this->generateProxyClasses();
if ($this->addGetService) {
$code = preg_replace("/\r?\n\r?\n public function __construct.+?\\{\r?\n/s", "\n protected \\Closure \$getService;\$0", $code, 1);
}
if ($this->asFiles) {
$fileTemplate = <<<EOF
<?php
use Symfony\\Component\\DependencyInjection\\Argument\\RewindableGenerator;
use Symfony\\Component\\DependencyInjection\\ContainerInterface;
use Symfony\\Component\\DependencyInjection\\Exception\\RuntimeException;
/*{<span class="php-variable">$this</span>-><span class="php-function-or-constant property member-of-self">docStar</span>}
* @internal This class has been auto-generated by the Symfony Dependency Injection Component.
*/
class %s extends {<span class="php-variable">$options</span>[<span class="php-string">'class'</span>]}
{%s}
EOF;
$files = [];
$preloadedFiles = [];
$ids = $this->container
->getRemovedIds();
foreach ($this->container
->getDefinitions() as $id => $definition) {
if (!$definition->isPublic() && '.' !== ($id[0] ?? '-')) {
$ids[$id] = true;
}
}
if ($ids = array_keys($ids)) {
sort($ids);
$c = "<?php\n\nreturn [\n";
foreach ($ids as $id) {
$c .= ' ' . $this->doExport($id) . " => true,\n";
}
$files['removed-ids.php'] = $c . "];\n";
}
if (!$this->inlineFactories) {
foreach ($this->generateServiceFiles($services) as $file => [
$c,
$preload,
]) {
$files[$file] = \sprintf($fileTemplate, substr($file, 0, -4), $c);
if ($preload) {
$preloadedFiles[$file] = $file;
}
}
foreach ($proxyClasses as $file => $c) {
$files[$file] = "<?php\n" . $c;
$preloadedFiles[$file] = $file;
}
}
$code .= $this->endClass();
if ($this->inlineFactories && $proxyClasses) {
$files['proxy-classes.php'] = "<?php\n\n";
foreach ($proxyClasses as $c) {
$files['proxy-classes.php'] .= $c;
}
}
$files[$options['class'] . '.php'] = $code;
$hash = ucfirst(strtr(ContainerBuilder::hash($files), '._', 'xx'));
$code = [];
foreach ($files as $file => $c) {
$code["Container{$hash}/{$file}"] = substr_replace($c, "<?php\n\nnamespace Container{$hash};\n", 0, 6);
if (isset($preloadedFiles[$file])) {
$preloadedFiles[$file] = "Container{$hash}/{$file}";
}
}
$namespaceLine = $this->namespace ? "\nnamespace {$this->namespace};\n" : '';
$time = $options['build_time'];
$id = hash('crc32', $hash . $time);
$this->asFiles = false;
if ($this->preload && null !== ($autoloadFile = $this->getAutoloadFile())) {
$autoloadFile = trim($this->export($autoloadFile), '()\\');
$preloadedFiles = array_reverse($preloadedFiles);
if ('' !== ($preloadedFiles = implode("';\nrequire __DIR__.'/", $preloadedFiles))) {
$preloadedFiles = "require __DIR__.'/{$preloadedFiles}';\n";
}
$code[$options['class'] . '.preload.php'] = <<<EOF
<?php
// This file has been auto-generated by the Symfony Dependency Injection Component
// You can reference it in the "opcache.preload" php.ini setting on PHP >= 7.4 when preloading is desired
use Symfony\\Component\\DependencyInjection\\Dumper\\Preloader;
if (in_array(PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
return;
}
require {<span class="php-variable">$autoloadFile</span>};
(require __DIR__.'/{<span class="php-variable">$options</span>[<span class="php-string">'class'</span>]}.php')->set(\\Container{<span class="php-variable">$hash</span>}\\{<span class="php-variable">$options</span>[<span class="php-string">'class'</span>]}::class, null);
{<span class="php-variable">$preloadedFiles</span>}
\$classes = [];
EOF;
foreach ($this->preload as $class) {
if (!$class || str_contains($class, '$') || \in_array($class, [
'int',
'float',
'string',
'bool',
'resource',
'object',
'array',
'null',
'callable',
'iterable',
'mixed',
'void',
], true)) {
continue;
}
if (!(class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false)) || (new \ReflectionClass($class))->isUserDefined()) {
$code[$options['class'] . '.preload.php'] .= \sprintf("\$classes[] = '%s';\n", $class);
}
}
$code[$options['class'] . '.preload.php'] .= <<<'EOF'
$preloaded = Preloader::preload($classes);
EOF;
}
$code[$options['class'] . '.php'] = <<<EOF
<?php
{<span class="php-variable">$namespaceLine</span>}
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
if (\\class_exists(\\Container{<span class="php-variable">$hash</span>}\\{<span class="php-variable">$options</span>[<span class="php-string">'class'</span>]}::class, false)) {
// no-op
} elseif (!include __DIR__.'/Container{<span class="php-variable">$hash</span>}/{<span class="php-variable">$options</span>[<span class="php-string">'class'</span>]}.php') {
touch(__DIR__.'/Container{<span class="php-variable">$hash</span>}.legacy');
return;
}
if (!\\class_exists({<span class="php-variable">$options</span>[<span class="php-string">'class'</span>]}::class, false)) {
\\class_alias(\\Container{<span class="php-variable">$hash</span>}\\{<span class="php-variable">$options</span>[<span class="php-string">'class'</span>]}::class, {<span class="php-variable">$options</span>[<span class="php-string">'class'</span>]}::class, false);
}
return new \\Container{<span class="php-variable">$hash</span>}\\{<span class="php-variable">$options</span>[<span class="php-string">'class'</span>]}([
'container.build_hash' => '{<span class="php-variable">$hash</span>}',
'container.build_id' => '{<span class="php-variable">$id</span>}',
'container.build_time' => {<span class="php-variable">$time</span>},
'container.runtime_mode' => \\in_array(\\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) ? 'web=0' : 'web=1',
], __DIR__.\\DIRECTORY_SEPARATOR.'Container{<span class="php-variable">$hash</span>}');
EOF;
}
else {
$code .= $this->endClass();
foreach ($proxyClasses as $c) {
$code .= $c;
}
}
$this->targetDirRegex = null;
$this->inlinedRequires = [];
$this->circularReferences = [];
$this->locatedIds = [];
$this->exportedVariables = [];
$this->dynamicParameters = [];
$this->preload = [];
$unusedEnvs = [];
foreach ($this->container
->getEnvCounters() as $env => $use) {
if (!$use) {
$unusedEnvs[] = $env;
}
}
if ($unusedEnvs) {
throw new EnvParameterException($unusedEnvs, null, 'Environment variables "%s" are never used. Please, check your container\'s configuration.');
}
return $code;
}