8000 Merge branch '4.4' into 5.0 · symfony/symfony@ea0eb11 · GitHub
[go: up one dir, main page]

Skip to content

Commit ea0eb11

Browse files
Merge branch '4.4' into 5.0
* 4.4: [DI] Fix CheckTypeDeclarationPass [Security/Http] don't require the session to be started when tracking its id [DI] fix preloading script generation
2 parents 079d85d + e457b24 commit ea0eb11

34 files changed

+313
-19
lines changed

src/Symfony/Bridge/Twig/Extension/TranslationExtension.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
use Twig\NodeVisitor\NodeVisitorInterface;
2222
use Twig\TwigFilter;
2323

24+
// Help opcache.preload discover always-needed symbols
25+
class_exists(TranslatorInterface::class);
26+
2427
/**
2528
* Provides integration of the Translation component with Twig.
2629
*

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerWeakRefPass;
2323
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
2424
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\WorkflowGuardListenerPass;
25+
use Symfony\Component\Cache\Adapter\ApcuAdapter;
26+
use Symfony\Component\Cache\Adapter\ArrayAdapter;
27+
use Symfony\Component\Cache\Adapter\ChainAdapter;
28+
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
29+
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
2530
use Symfony\Component\Cache\DependencyInjection\CacheCollectorPass;
2631
use Symfony\Component\Cache\DependencyInjection\CachePoolClearerPass;
2732
use Symfony\Component\Cache\DependencyInjection\CachePoolPass;
@@ -31,6 +36,7 @@
3136
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
3237
use Symfony\Component\DependencyInjection\Compiler\RegisterReverseContainerPass;
3338
use Symfony\Component\DependencyInjection\ContainerBuilder;
39+
use Symfony\Component\Dotenv\Dotenv;
3440
use Symfony\Component\ErrorHandler\ErrorHandler;
3541
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
3642
use Symfony\Component\Form\DependencyInjection\FormPass;
@@ -57,6 +63,19 @@
5763
use Symfony\Component\Validator\DependencyInjection\AddAutoMappingConfigurationPass;
5864
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
5965
use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass;
66+
use Symfony\Component\VarExporter\Internal\Hydrator;
67+
use Symfony\Component\VarExporter\Internal\Registry;
68+
69+
// Help opcache.preload discover always-needed symbols
70+
class_exists(ApcuAdapter::class);
71+
class_exists(ArrayAdapter::class);
72+
class_exists(ChainAdapter::class);
73+
class_exists(PhpArrayAdapter::class);
74+
class_exists(PhpFilesAdapter::class);
75+
class_exists(Dotenv::class);
76+
class_exists(ErrorHandler::class);
77+
class_exists(Hydrator::class);
78+
class_exists(Registry::class);
6079

6180
/**
6281
* Bundle.

src/Symfony/Bundle/FrameworkBundle/Routing/Router.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,16 @@
1919
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
2020
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2121
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
22+
use Symfony\Component\Routing\Annotation\Route;
2223
use Symfony\Component\Routing\RequestContext;
2324
use Symfony\Component\Routing\RouteCollection;
2425
use Symfony\Component\Routing\Router as BaseRouter;
2526
use Symfony\Contracts\Service\ServiceSubscriberInterface;
2627

28+
// Help opcache.preload discover always-needed symbols
29+
class_exists(RedirectableCompiledUrlMatcher::class);
30+
class_exists(Route::class);
31+
2732
/**
2833
* This Router creates the Loader only when the cache is empty.
2934
*

src/Symfony/Bundle/TwigBundle/TwigBundle.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@
1919
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
2020
use Symfony\Component\DependencyInjection\ContainerBuilder;
2121
use Symfony\Component\HttpKernel\Bundle\Bundle;
22+
use Twig\Cache\FilesystemCache;
23+
use Twig\Extension\CoreExtension;
24+
use Twig\Extension\EscaperExtension;
25+
use Twig\Extension\OptimizerExtension;
26+
use Twig\Extension\StagingExtension;
27+
use Twig\ExtensionSet;
28+
29+
// Help opcache.preload discover always-needed symbols
30+
class_exists(FilesystemCache::class);
31+
class_exists(CoreExtension::class);
32+
class_exists(EscaperExtension::class);
33+
class_exists(OptimizerExtension::class);
34+
class_exists(StagingExtension::class);
35+
class_exists(ExtensionSet::class);
2236

2337
/**
2438
* Bundle.

src/Symfony/Component/Cache/Adapter/AdapterInterface.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
use Psr\Cache\CacheItemPoolInterface;
1515
use Symfony\Component\Cache\CacheItem;
1616

17+
// Help opcache.preload discover always-needed symbols
18+
class_exists(CacheItem::class);
19+
1720
/**
1821
* Interface for adapters managing instances of Symfony's CacheItem.
1922
*

src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
1818
use Symfony\Component\DependencyInjection\Container;
1919
use Symfony\Component\DependencyInjection\Definition;
20-
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
2120
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
2221
use Symfony\Component\DependencyInjection\Exception\InvalidParameterTypeException;
2322
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
@@ -207,7 +206,7 @@ private function checkType(Definition $checkedDefinition, $value, \ReflectionPar
207206
if ('' === preg_replace('/'.$envPlaceholderUniquePrefix.'_\w+_[a-f0-9]{32}/U', '', $value, -1, $c) && 1 === $c) {
208207
try {
209208
$value = $this->container->resolveEnvPlaceholders($value, true);
210-
} catch (EnvNotFoundException | RuntimeException $e) {
209+
} catch (\Exception $e) {
211210
// If an env placeholder cannot be resolved, we skip the validation.
212211
return;
213212
}
@@ -250,7 +249,11 @@ private function checkType(Definition $checkedDefinition, $value, \ReflectionPar
250249
return;
251250
}
252251

253-
if ('iterable' === $type && (\is_array($value) || is_subclass_of($class, \Traversable::class))) {
252+
if ('iterable' === $type && (\is_array($value) || 'array' === $class || is_subclass_of($class, \Traversable::class))) {
253+
return;
254+
}
255+
256+
if ($type === $class) {
254257
return;
255258
}
256259

src/Symfony/Component/DependencyInjection/Container.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\DependencyInjection;
1313

14+
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
15+
use Symfony\Component\DependencyInjection\Argument\ServiceLocator as ArgumentServiceLocator;
1416
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
1517
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
1618
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
@@ -22,6 +24,10 @@
2224
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
2325
use Symfony\Contracts\Service\ResetInterface;
2426

27+
// Help opcache.preload discover always-needed symbols
28+
class_exists(RewindableGenerator::class);
29+
class_exists(ArgumentServiceLocator::class);
30+
2531
/**
2632
* Container is a dependency injection container.
2733
*

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 67 additions & 14 deletions
10000
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class PhpDumper extends Dumper
8282
private $inlinedRequires = [];
8383
private $circularReferences = [];
8484
private $singleUsePrivateIds = [];
85+
private $preload = [];
8586
private $addThrow = false;
8687
private $addGetService = false;
8788
private $locatedIds = [];
@@ -143,6 +144,7 @@ public function dump(array $options = [])
143144
'hot_path_tag' => 'container.hot_path',
144145
D7AE 'inline_factories_parameter' => 'container.dumper.inline_factories',
145146
'inline_class_loader_parameter' => 'container.dumper.inline_class_loader',
147+
'preload_classes' => [],
146148
'service_locator_tag' => 'container.service_locator',
147149
'build_time' => time(),
148150
], $options);
@@ -227,8 +229,12 @@ public function dump(array $options = [])
227229

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

232+
if ($options['preload_classes']) {
233+
$this->preload = array_combine($options['preload_classes'], $options['preload_classes']);
234+
}
235+
230236
$code =
231-
$this->startClass($options['class'], $baseClass, $preload).
237+
$this->startClass($options['class'], $baseClass).
232238
$this->addServices($services).
233239
$this->addDeprecatedAliases().
234240
$this->addDefaultParametersMethod()
@@ -303,7 +309,7 @@ public function dump(array $options = [])
303309
$id = hash('crc32', $hash.$time);
304310
$this->asFiles = false;
305311

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

309315
$code[$options['class'].'.preload.php'] = <<<EOF
@@ -321,8 +327,13 @@ public function dump(array $options = [])
321327
322328
EOF;
323329

324-
foreach ($preload as $class) {
325-
$code[$options['class'].'.preload.php'] .= sprintf("\$classes[] = '%s';\n", $class);
330+
foreach ($this->preload as $class) {
331+
if (!$class || false !== strpos($class, '$')) {
332+
continue;
333+
}
334+
if (!(class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false)) || (new \ReflectionClass($class))->isUserDefined()) {
335+
$code[$options['class'].'.preload.php'] .= sprintf("\$classes[] = '%s';\n", $class);
336+
}
326337
}
327338

328339
$code[$options['class'].'.preload.php'] .= <<<'EOF'
@@ -368,6 +379,7 @@ public function dump(array $options = [])
368379
$this->circularReferences = [];
369380
$this->locatedIds = [];
370381
$this->exportedVariables = [];
382+
$this->preload = [];
371383

372384
$unusedEnvs = [];
373385
foreach ($this->container->getEnvCounters() as $env => $use) {
@@ -546,8 +558,10 @@ private function addServiceInclude(string $cId, Definition $definition): string
546558
if ($this->inlineRequires && (!$this->isHotPath($definition) || $this->getProxyDumper()->isProxyCandidate($definition))) {
547559
$lineage = [];
548560
foreach ($this->inlinedDefinitions as $def) {
549-
if (!$def->isDeprecated() && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
550-
$this->collectLineage($class, $lineage);
561+
if (!$def->isDeprecated()) {
562+
foreach ($this->getClasses($def) as $class) {
563+
$this->collectLineage($class, $lineage);
564+
}
551565
}
552566
}
553567

@@ -556,9 +570,10 @@ private function addServiceInclude(string $cId, Definition $definition): string
556570
&& ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior
557571
&& $this->container->has($id)
558572
&& $this->isTrivialInstance($def = $this->container->findDefinition($id))
559-
&& \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())
560573
) {
561-
$this->collectLineage($class, $lineage);
574+
foreach ($this->getClasses($def) as $class) {
575+
$this->collectLineage($class, $lineage);
576+
}
562577
}
563578
}
564579

@@ -808,6 +823,12 @@ protected function {$methodName}($lazyInitialization)
808823

809824
if ($definition->isDeprecated()) {
810825
$code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id)));
826+
} else {
827+
foreach ($this->inlinedDefinitions as $def) {
828+
foreach ($this->getClasses($def) as $class) {
829+
$this->preload[$class] = $class;
830+
}
831+
}
811832
}
812833

813834
if ($this->getProxyDumper()->isProxyCandidate($definition)) {
@@ -964,7 +985,15 @@ private function addServices(array &$services = null): string
964985
$definitions = $this->container->getDefinitions();
965986
ksort($definitions);
966987
foreach ($definitions as $id => $definition) {
967-
$services[$id] = $definition->isSynthetic() ? null : $this->addService($id, $definition);
988+
if (!$definition->isSynthetic()) {
989+
$services[$id] = $this->addService($id, $definition);
990+
} else {
991+
$services[$id] = null;
992+
993+
foreach ($this->getClasses($definition) as $class) {
994+
$this->preload[$class] = $class;
995+
}
996+
}
968997
}
969998

970999
foreach ($definitions as $id => $definition) {
@@ -1065,7 +1094,7 @@ private function addNewInstance(Definition $definition, string $return = '', str
10651094
return $return.sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)).$tail;
10661095
}
10671096

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

@@ -1128,7 +1157,7 @@ public function __construct()
11281157
$code .= $this->addMethodMap();
11291158
$code .= $this->asFiles && !$this->inlineFactories ? $this->addFileMap() : '';
11301159
$code .= $this->addAliases();
1131-
$code .= $this->addInlineRequires($preload);
1160+
$code .= $this->addInlineRequires();
11321161
$code .= <<<EOF
11331162
}
11341163
@@ -1328,7 +1357,7 @@ protected function {$methodNameAlias}()
13281357
return $code;
13291358
}
13301359

1331-
private function addInlineRequires(?array &$preload): string
1360+
private function addInlineRequires(): string
13321361
{
13331362
if (!$this->hotPathTag || !$this->inlineRequires) {
13341363
return '';
@@ -1346,8 +1375,7 @@ private function addInlineRequires(?array &$preload): string
13461375
$inlinedDefinitions = $this->getDefinitionsFromArguments([$definition]);
13471376

13481377
foreach ($inlinedDefinitions as $def) {
1349-
if (\is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
1350-
$preload[$class] = $class;
1378+
foreach ($this->getClasses($def) as $class) {
13511379
$this->collectLineage($class, $lineage);
13521380
}
13531381
}
@@ -2067,4 +2095,29 @@ private function getAutoloadFile(): ?string
20672095

20682096
return null;
20692097
}
2098+
2099+
private function getClasses(Definition $definition): array
2100+
{
2101+
$classes = [];
2102+
2103+
while ($definition instanceof Definition) {
2104+
$classes[] = trim($definition->getClass(), '\\');
2105+
$factory = $definition->getFactory();
2106+
2107+
if (!\is_array($factory)) {
2108+
$factory = [$factory];
2109+
}
2110+
2111+
if (\is_string($factory[0])) {
2112+
if (false !== $i = strrpos($factory[0], '::')) {
2113+
$factory[0] = substr($factory[0], 0, $i);
2114+
}
2115+
$classes[] = trim($factory[0], '\\');
2116+
}
2117+
2118+
$definition = $factory[0];
2119+
}
2120+
2121+
return array_filter($classes);
2122+
}
20702123
}

src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,42 @@ public function testProcessFactoryDoesNotLoadCodeByDefault()
536536
$this->addToAssertionCount(1);
537537
}
538538

539+
public function testProcessFactoryForTypeSameAsClass()
540+
{
541+
$container = new ContainerBuilder();
542+
543+
$container->register('foo', Foo::class);
544+
$container->register('bar', 'callable')
545+
->setFactory([
546+
new Reference('foo'),
547+
'createCallable',
548+
]);
549+
$container->register('bar_call', BarMethodCall::class)
550+
->addMethodCall('setCallable', [new Reference('bar')]);
551+
552+
(new CheckTypeDeclarationsPass(true))->process($container);
553+
554+
$this->addToAssertionCount(1);
555+
}
556+
557+
public function testProcessFactoryForIterableTypeAndArrayClass()
558+
{
559+
$container = new ContainerBuilder();
560+
561+
$container->register('foo', Foo::class);
562+
$container->register('bar', 'array')
563+
->setFactory([
564+
new Reference('foo'),
565+
'createArray',
566+
]);
567+
$container->register('bar_call', BarMethodCall::class)
568+
->addMethodCall('setIterable', [new Reference('bar')]);
569+
570+
(new CheckTypeDeclarationsPass(true))->process($container);
571+
572+
$this->addToAssertionCount(1);
573+
}
574+
539575
public function testProcessPassingBuiltinTypeDoesNotLoadCodeByDefault()
540576
{
541577
$container = new ContainerBuilder();

src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/Foo.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,14 @@ public static function createBarArguments(\stdClass $stdClass, \stdClass $stdCla
1313
{
1414
return new Bar($stdClass);
1515
}
16+
17+
public static function createCallable(): callable
18+
{
19+
return function() {};
20+
}
21+
22+
public static function createArray(): array
23+
{
24+
return [];
25+
}
1626
}

0 commit comments

Comments
 (0)
0