Skip to content

Commit f004895

Browse files
committed
bug #25858 [DI] Fix initialization of legacy containers by delaying include_once (nicolas-grekas)
This PR was merged into the 3.4 branch. Discussion ---------- [DI] Fix initialization of legacy containers by delaying include_once | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Best reviewed ignoring whitespaces: https://github.com/symfony/symfony/pull/25858/files?w=1 Noticed while removing a package: silencing the failing `include_once` as introduced in #25255 is not working for the `$oldContainer` in `Kernel`, and fails with a fatal error when an include succeeds but the class inside misses a parent. Delaying the calls to `include_once` to the moment where the fresh container is actually used first, when setting the "kernel" service, works around the situation. Commits ------- 5e750ec [DI] Fix initialization of legacy containers by delaying include_once
2 parents 8d4e3c5 + 5e750ec commit f004895

File tree

4 files changed

+79
-59
lines changed

4 files changed

+79
-59
lines changed

src/Symfony/Component/DependencyInjection/Container.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,13 @@ public function setParameter($name, $value)
167167
*/
168168
public function set($id, $service)
169169
{
170+
// Runs the internal initializer; used by the dumped container to include always-needed files
171+
if (isset($this->privates['service_container']) && $this->privates['service_container'] instanceof \Closure) {
172+
$initialize = $this->privates['service_container'];
173+
unset($this->privates['service_container']);
174+
$initialize();
175+
}
176+
170177
$id = $this->normalizeId($id);
171178

172179
if ('service_container' === $id) {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,16 +1243,16 @@ private function addInlineRequires()
12431243
}
12441244
}
12451245

1246-
$code = "\n";
1246+
$code = '';
12471247

12481248
foreach ($lineage as $file) {
12491249
if (!isset($this->inlinedRequires[$file])) {
12501250
$this->inlinedRequires[$file] = true;
1251-
$code .= sprintf(" include_once %s;\n", $file);
1251+
$code .= sprintf("\n include_once %s;", $file);
12521252
}
12531253
}
12541254

1255-
return "\n" === $code ? '' : $code;
1255+
return $code ? sprintf("\n \$this->privates['service_container'] = function () {%s\n };\n", $code) : '';
12561256
}
12571257

12581258
/**

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_requires.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@ public function __construct()
4646

4747
$this->aliases = array();
4848

49-
include_once $this->targetDirs[1].'/includes/HotPath/I1.php';
50-
include_once $this->targetDirs[1].'/includes/HotPath/P1.php';
51-
include_once $this->targetDirs[1].'/includes/HotPath/T1.php';
52-
include_once $this->targetDirs[1].'/includes/HotPath/C1.php';
49+
$this->privates['service_container'] = function () {
50+
include_once $this->targetDirs[1].'/includes/HotPath/I1.php';
51+
include_once $this->targetDirs[1].'/includes/HotPath/P1.php';
52+
include_once $this->targetDirs[1].'/includes/HotPath/T1.php';
53+
include_once $this->targetDirs[1].'/includes/HotPath/C1.php';
54+
};
5355
}
5456

5557
public function getRemovedIds()

src/Symfony/Component/HttpKernel/Kernel.php

Lines changed: 63 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -581,80 +581,91 @@ protected function initializeContainer()
581581
$class = $this->getContainerClass();
582582
$cacheDir = $this->warmupDir ?: $this->getCacheDir();
583583
$cache = new ConfigCache($cacheDir.'/'.$class.'.php', $this->debug);
584+
$oldContainer = null;
584585
if ($fresh = $cache->isFresh()) {
585586
// Silence E_WARNING to ignore "include" failures - don't use "@" to prevent silencing fatal errors
586587
$errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
588+
$fresh = $oldContainer = false;
587589
try {
588-
$this->container = include $cache->getPath();
590+
if (\is_object($this->container = include $cache->getPath())) {
591+
$this->container->set('kernel', $this);
592+
$oldContainer = $this->container;
593+
$fresh = true;
594+
}
595+
} catch (\Throwable $e) {
596+
} catch (\Exception $e) {
589597
} finally {
590598
error_reporting($errorLevel);
591599
}
592-
$fresh = \is_object($this->container);
593600
}
594-
if (!$fresh) {
595-
if ($this->debug) {
596-
$collectedLogs = array();
597-
$previousHandler = defined('PHPUNIT_COMPOSER_INSTALL');
598-
$previousHandler = $previousHandler ?: set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) {
599-
if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) {
600-
return $previousHandler ? $previousHandler($type & ~E_WARNING, $message, $file, $line) : E_WARNING === $type;
601-
}
602601

603-
if (isset($collectedLogs[$message])) {
604-
++$collectedLogs[$message]['count'];
602+
if ($fresh) {
603+
return;
604+
}
605605

606-
return;
607-
}
606+
if ($this->debug) {
607+
$collectedLogs = array();
608+
$previousHandler = defined('PHPUNIT_COMPOSER_INSTALL');
609+
$previousHandler = $previousHandler ?: set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) {
610+
if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) {
611+
return $previousHandler ? $previousHandler($type, $message, $file, $line) : false;
612+
}
613+
614+
if (isset($collectedLogs[$message])) {
615+
++$collectedLogs[$message]['count'];
616+
617+
return;
618+
}
608619

609-
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
610-
// Clean the trace by removing first frames added by the error handler itself.
611-
for ($i = 0; isset($backtrace[$i]); ++$i) {
612-
if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
613-
$backtrace = array_slice($backtrace, 1 + $i);
614-
break;
615-
}
620+
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
621+
// Clean the trace by removing first frames added by the error handler itself.
622+
for ($i = 0; isset($backtrace[$i]); ++$i) {
623+
if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
624+
$backtrace = array_slice($backtrace, 1 + $i);
625+
break;
616626
}
627+
}
617628

618-
$collectedLogs[$message] = array(
619-
'type' => $type,
620-
'message' => $message,
621-
'file' => $file,
622-
'line' => $line,
623-
'trace' => $backtrace,
624-
'count' => 1,
625-
);
626-
});
627-
} else {
628-
$errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
629+
$collectedLogs[$message] = array(
630+
'type' => $type,
631+
'message' => $message,
632+
'file' => $file,
633+
'line' => $line,
634+
'trace' => $backtrace,
635+
'count' => 1,
636+
);
637+
});
638+
}
639+
640+
try {
641+
$container = null;
642+
$container = $this->buildContainer();
643+
$container->compile();
644+
} finally {
645+
if ($this->debug && true !== $previousHandler) {
646+
restore_error_handler();
647+
648+
file_put_contents($cacheDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs)));
649+
file_put_contents($cacheDir.'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : '');
629650
}
651+
}
630652

653+
if (null === $oldContainer) {
654+
$errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
631655
try {
632-
$container = null;
633-
$container = $this->buildContainer();
634-
$container->compile();
635-
636-
$oldContainer = file_exists($cache->getPath()) && is_object($oldContainer = include $cache->getPath()) ? new \ReflectionClass($oldContainer) : false;
656+
$oldContainer = include $cache->getPath();
657+
} catch (\Throwable $e) {
658+
} catch (\Exception $e) {
637659
} finally {
638-
if (!$this->debug) {
639-
error_reporting($errorLevel);
640-
} elseif (true !== $previousHandler) {
641-
restore_error_handler();
642-
643-
file_put_contents($cacheDir.'/'.$class.'Deprecations.log', serialize(array_values($collectedLogs)));
644-
file_put_contents($cacheDir.'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : '');
645-
}
660+
error_reporting($errorLevel);
646661
}
647-
648-
$this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
649-
$this->container = require $cache->getPath();
650662
}
663+
$oldContainer = is_object($oldContainer) ? new \ReflectionClass($oldContainer) : false;
651664

665+
$this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
666+
$this->container = require $cache->getPath();
652667
$this->container->set('kernel', $this);
653668

654-
if ($fresh) {
655-
return;
656-
}
657-
658669
if ($oldContainer && get_class($this->container) !== $oldContainer->name) {
659670
// Because concurrent requests might still be using them,
660671
// old container files are not removed immediately,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy