Skip to content

Commit

Permalink
[DI] fix preloading script generation
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolas-grekas committed Mar 17, 2020
1 parent 46e441f commit d443a87
Show file tree
Hide file tree
Showing 30 changed files with 217 additions and 14 deletions.
2 changes: 2 additions & 0 deletions src/Symfony/Bridge/Twig/Extension/TranslationExtension.php
Expand Up @@ -24,6 +24,8 @@
use Twig\TokenParser\AbstractTokenParser;
use Twig\TwigFilter;

class_exists(TranslatorInterface::class);

/**
* Provides integration of the Translation component with Twig.
*
Expand Down
18 changes: 18 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
Expand Up @@ -23,6 +23,11 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerWeakRefPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\WorkflowGuardListenerPass;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
use Symfony\Component\Cache\DependencyInjection\CacheCollectorPass;
use Symfony\Component\Cache\DependencyInjection\CachePoolClearerPass;
use Symfony\Component\Cache\DependencyInjection\CachePoolPass;
Expand All @@ -32,6 +37,7 @@
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\Compiler\RegisterReverseContainerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\ErrorHandler\ErrorHandler;
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
use Symfony\Component\Form\DependencyInjection\FormPass;
Expand All @@ -58,6 +64,18 @@
use Symfony\Component\Validator\DependencyInjection\AddAutoMappingConfigurationPass;
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass;
use Symfony\Component\VarExporter\Internal\Hydrator;
use Symfony\Component\VarExporter\Internal\Registry;

class_exists(ApcuAdapter::class);
class_exists(ArrayAdapter::class);
class_exists(ChainAdapter::class);
class_exists(PhpArrayAdapter::class);
class_exists(PhpFilesAdapter::class);
class_exists(Dotenv::class);
class_exists(ErrorHandler::class);
class_exists(Hydrator::class);
class_exists(Registry::class);

/**
* Bundle.
Expand Down
4 changes: 4 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Routing/Router.php
Expand Up @@ -20,10 +20,14 @@
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Router as BaseRouter;

class_exists(RedirectableCompiledUrlMatcher::class);
class_exists(Route::class);

/**
* This Router creates the Loader only when the cache is empty.
*
Expand Down
13 changes: 13 additions & 0 deletions src/Symfony/Bundle/TwigBundle/TwigBundle.php
Expand Up @@ -20,6 +20,19 @@
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Twig\Cache\FilesystemCache;
use Twig\Extension\CoreExtension;
use Twig\Extension\EscaperExtension;
use Twig\Extension\OptimizerExtension;
use Twig\Extension\StagingExtension;
use Twig\ExtensionSet;

class_exists(FilesystemCache::class);
class_exists(CoreExtension::class);
class_exists(EscaperExtension::class);
class_exists(OptimizerExtension::class);
class_exists(StagingExtension::class);
class_exists(ExtensionSet::class);

/**
* Bundle.
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Cache/Adapter/AdapterInterface.php
Expand Up @@ -14,6 +14,8 @@
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;

class_exists(CacheItem::class);

/**
* Interface for adapters managing instances of Symfony's CacheItem.
*
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/DependencyInjection/Container.php
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Argument\ServiceLocator as ArgumentServiceLocator;
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
Expand All @@ -22,6 +24,9 @@
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Contracts\Service\ResetInterface;

class_exists(RewindableGenerator::class);
class_exists(ArgumentServiceLocator::class);

/**
* Container is a dependency injection container.
*
Expand Down
78 changes: 64 additions & 14 deletions src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
Expand Up @@ -81,6 +81,7 @@ class PhpDumper extends Dumper
private $inlinedRequires = [];
private $circularReferences = [];
private $singleUsePrivateIds = [];
private $preload = [];
private $addThrow = false;
private $addGetService = false;
private $locatedIds = [];
Expand Down Expand Up @@ -142,6 +143,7 @@ public function dump(array $options = [])
'hot_path_tag' => 'container.hot_path',
'inline_factories_parameter' => 'container.dumper.inline_factories',
'inline_class_loader_parameter' => 'container.dumper.inline_class_loader',
'preload_classes' => [],
'service_locator_tag' => 'container.service_locator',
'build_time' => time(),
], $options);
Expand Down Expand Up @@ -226,8 +228,12 @@ public function dump(array $options = [])

$proxyClasses = $this->inlineFactories ? $this->generateProxyClasses() : null;

if ($options['preload_classes']) {
$this->preload = array_combine($options['preload_classes'], $options['preload_classes']);
}

$code =
$this->startClass($options['class'], $baseClass, $preload).
$this->startClass($options['class'], $baseClass).
$this->addServices($services).
$this->addDeprecatedAliases().
$this->addDefaultParametersMethod()
Expand Down Expand Up @@ -302,7 +308,7 @@ public function dump(array $options = [])
$id = hash('crc32', $hash.$time);
$this->asFiles = false;

if ($preload && null !== $autoloadFile = $this->getAutoloadFile()) {
if ($this->preload && null !== $autoloadFile = $this->getAutoloadFile()) {
$autoloadFile = substr($this->export($autoloadFile), 2, -1);

$code[$options['class'].'.preload.php'] = <<<EOF
Expand All @@ -320,8 +326,10 @@ public function dump(array $options = [])
EOF;

foreach ($preload as $class) {
$code[$options['class'].'.preload.php'] .= sprintf("\$classes[] = '%s';\n", $class);
foreach ($this->preload as $class) {
if ($class && (!(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'
Expand Down Expand Up @@ -367,6 +375,7 @@ public function dump(array $options = [])
$this->circularReferences = [];
$this->locatedIds = [];
$this->exportedVariables = [];
$this->preload = [];

$unusedEnvs = [];
foreach ($this->container->getEnvCounters() as $env => $use) {
Expand Down Expand Up @@ -542,8 +551,10 @@ private function addServiceInclude(string $cId, Definition $definition): string
if ($this->inlineRequires && (!$this->isHotPath($definition) || $this->getProxyDumper()->isProxyCandidate($definition))) {
$lineage = [];
foreach ($this->inlinedDefinitions as $def) {
if (!$def->isDeprecated() && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
$this->collectLineage($class, $lineage);
if (!$def->isDeprecated()) {
foreach ($this->getClasses($def) as $class) {
$this->collectLineage($class, $lineage);
}
}
}

Expand All @@ -552,9 +563,10 @@ private function addServiceInclude(string $cId, Definition $definition): string
&& ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior
&& $this->container->has($id)
&& $this->isTrivialInstance($def = $this->container->findDefinition($id))
&& \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())
) {
$this->collectLineage($class, $lineage);
foreach ($this->getClasses($def) as $class) {
$this->collectLineage($class, $lineage);
}
}
}

Expand Down Expand Up @@ -804,6 +816,12 @@ protected function {$methodName}($lazyInitialization)

if ($definition->isDeprecated()) {
$code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id)));
} else {
foreach ($this->inlinedDefinitions as $def) {
foreach ($this->getClasses($def) as $class) {
$this->preload[$class] = $class;
}
}
}

if ($this->getProxyDumper()->isProxyCandidate($definition)) {
Expand Down Expand Up @@ -960,7 +978,15 @@ private function addServices(array &$services = null): string
$definitions = $this->container->getDefinitions();
ksort($definitions);
foreach ($definitions as $id => $definition) {
$services[$id] = $definition->isSynthetic() ? null : $this->addService($id, $definition);
if (!$definition->isSynthetic()) {
$services[$id] = $this->addService($id, $definition);
} else {
$services[$id] = null;

foreach ($this->getClasses($definition) as $class) {
$this->preload[$class] = $class;
}
}
}

foreach ($definitions as $id => $definition) {
Expand Down Expand Up @@ -1061,7 +1087,7 @@ private function addNewInstance(Definition $definition, string $return = '', str
return $return.sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)).$tail;
}

private function startClass(string $class, string $baseClass, ?array &$preload): string
private function startClass(string $class, string $baseClass): string
{
$namespaceLine = !$this->asFiles && $this->namespace ? "\nnamespace {$this->namespace};\n" : '';

Expand Down Expand Up @@ -1124,7 +1150,7 @@ public function __construct()
$code .= $this->addMethodMap();
$code .= $this->asFiles && !$this->inlineFactories ? $this->addFileMap() : '';
$code .= $this->addAliases();
$code .= $this->addInlineRequires($preload);
$code .= $this->addInlineRequires();
$code .= <<<EOF
}
Expand Down Expand Up @@ -1324,7 +1350,7 @@ protected function {$methodNameAlias}()
return $code;
}

private function addInlineRequires(?array &$preload): string
private function addInlineRequires(): string
{
if (!$this->hotPathTag || !$this->inlineRequires) {
return '';
Expand All @@ -1342,8 +1368,7 @@ private function addInlineRequires(?array &$preload): string
$inlinedDefinitions = $this->getDefinitionsFromArguments([$definition]);

foreach ($inlinedDefinitions as $def) {
if (\is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
$preload[$class] = $class;
foreach ($this->getClasses($def) as $class) {
$this->collectLineage($class, $lineage);
}
}
Expand Down Expand Up @@ -2065,4 +2090,29 @@ private function getAutoloadFile(): ?string

return null;
}

private function getClasses(Definition $definition): array
{
$classes = [];

while ($definition instanceof Definition) {
$classes[] = trim($definition->getClass(), '\\');
$factory = $definition->getFactory();

if (!\is_array($factory)) {
$factory = [$factory];
}

if (\is_string($factory[0])) {
if (false !== $i = strrpos($factory[0], '::')) {
$factory[0] = substr($factory[0], 0, $i);
}
$classes[] = trim($factory[0], '\\');
}

$definition = $factory[0];
}

return array_filter($classes);
}
}
Expand Up @@ -531,6 +531,24 @@ class ProjectServiceContainer extends Container
}
}

[ProjectServiceContainer.preload.php] => <?php
%A

$classes = [];
$classes[] = 'Bar\FooClass';
$classes[] = 'Baz';
$classes[] = 'ConfClass';
$classes[] = 'Bar';
$classes[] = 'BazClass';
$classes[] = 'Foo';
$classes[] = 'LazyContext';
$classes[] = 'FooBarBaz';
$classes[] = 'FactoryClass';
$classes[] = 'Request';
$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface';

%A

[ProjectServiceContainer.php] => <?php

// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
Expand Down
Expand Up @@ -536,6 +536,16 @@ class ProjectServiceContainer extends Container

$classes = [];
$classes[] = 'Bar\FooClass';
$classes[] = 'Baz';
$classes[] = 'ConfClass';
$classes[] = 'Bar';
$classes[] = 'BazClass';
$classes[] = 'Foo';
$classes[] = 'LazyContext';
$classes[] = 'FooBarBaz';
$classes[] = 'FactoryClass';
$classes[] = 'Request';
$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface';

%A

Expand Down
Expand Up @@ -165,6 +165,16 @@ class FooClass_%s extends \Bar\FooClass implements \ProxyManager\Proxy\VirtualPr
%A
}

[ProjectServiceContainer.preload.php] => <?php
%A

$classes = [];
$classes[] = 'Bar\FooClass';
$classes[] = 'Bar\FooLazyClass';
$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface';

%A

[ProjectServiceContainer.php] => <?php

// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
Expand Down
Expand Up @@ -83,6 +83,15 @@ class ProjectServiceContainer extends Container
}
}

[ProjectServiceContainer.preload.php] => <?php
%A

$classes = [];
$classes[] = 'Bar\FooLazyClass';
$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface';

%A

[ProjectServiceContainer.php] => <?php

// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
Expand Down
Expand Up @@ -15,6 +15,8 @@
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;

class_exists(CliDumper::class);

/**
* @author Nicolas Grekas <p@tchwork.com>
*/
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/HttpFoundation/AcceptHeader.php
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Component\HttpFoundation;

class_exists(AcceptHeaderItem::class);

/**
* Represents an Accept-* header.
*
Expand Down

0 comments on commit d443a87

Please sign in to comment.