From ea52a409949ad88625a53edde5d2e8e037dd7578 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 25 Mar 2020 18:08:12 +0100 Subject: [PATCH] [HttpKernel] allow cache warmers to add to the list of preloaded classes and files --- UPGRADE-5.1.md | 6 +++++ UPGRADE-6.0.md | 5 ++++ .../Doctrine/CacheWarmer/ProxyCacheWarmer.php | 11 ++++++++ .../AbstractPhpFileCacheWarmer.php | 9 +++++-- .../CachePoolClearerCacheWarmer.php | 6 ++++- .../CacheWarmer/RouterCacheWarmer.php | 6 ++--- .../CacheWarmer/TranslationsCacheWarmer.php | 6 ++++- .../CacheWarmer/ValidatorCacheWarmer.php | 5 +++- .../Command/CacheClearCommand.php | 7 +++-- .../Bundle/FrameworkBundle/Routing/Router.php | 12 +++++---- .../Translation/Translator.php | 4 +++ .../CacheWarmer/ExpressionCacheWarmer.php | 5 ++++ .../CacheWarmer/TemplateCacheWarmer.php | 12 ++++++++- .../Cache/Adapter/PhpArrayAdapter.php | 7 ++++- .../DependencyInjection/CHANGELOG.md | 1 + .../DependencyInjection/Dumper/Preloader.php | 27 ++++++++++++++++--- src/Symfony/Component/HttpKernel/CHANGELOG.md | 2 ++ .../CacheWarmer/CacheWarmerAggregate.php | 9 ++++++- .../CacheWarmer/WarmableInterface.php | 2 ++ src/Symfony/Component/HttpKernel/Kernel.php | 7 ++++- .../Tests/CacheWarmer/CacheWarmerTest.php | 5 ++++ .../Translation/DataCollectorTranslator.php | 6 ++++- .../Component/VarExporter/CHANGELOG.md | 5 ++++ .../Component/VarExporter/VarExporter.php | 7 +++-- 24 files changed, 146 insertions(+), 26 deletions(-) diff --git a/UPGRADE-5.1.md b/UPGRADE-5.1.md index 96c1c8b0e2d90..7f61135f4b917 100644 --- a/UPGRADE-5.1.md +++ b/UPGRADE-5.1.md @@ -39,6 +39,12 @@ HttpFoundation `__construct()` instead) * Made the Mime component an optional dependency +HttpKernel +---------- + + * Made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+ + not returning an array is deprecated + Mailer ------ diff --git a/UPGRADE-6.0.md b/UPGRADE-6.0.md index 4180954165f54..2112ed258b5dd 100644 --- a/UPGRADE-6.0.md +++ b/UPGRADE-6.0.md @@ -36,6 +36,11 @@ HttpFoundation `RedirectResponse::create()`, and `StreamedResponse::create()` methods (use `__construct()` instead) +HttpKernel +---------- + + * Made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+ + Messenger --------- diff --git a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php index 0a90bc1a3f86c..bca2ea2c170da 100644 --- a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php +++ b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php @@ -43,9 +43,12 @@ public function isOptional() /** * {@inheritdoc} + * + * @return string[] A list of files to preload on PHP 7.4+ */ public function warmUp(string $cacheDir) { + $files = []; foreach ($this->registry->getManagers() as $em) { // we need the directory no matter the proxy cache generation strategy if (!is_dir($proxyCacheDir = $em->getConfiguration()->getProxyDir())) { @@ -64,6 +67,14 @@ public function warmUp(string $cacheDir) $classes = $em->getMetadataFactory()->getAllMetadata(); $em->getProxyFactory()->generateProxyClasses($classes); + + foreach (scandir($proxyCacheDir) as $file) { + if (!is_dir($file = $proxyCacheDir.'/'.$file)) { + $files[] = $file; + } + } } + + return $files; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AbstractPhpFileCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AbstractPhpFileCacheWarmer.php index 0e4561ad4754b..f4089aa694057 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AbstractPhpFileCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AbstractPhpFileCacheWarmer.php @@ -42,6 +42,8 @@ public function isOptional() /** * {@inheritdoc} + * + * @return string[] A list of classes to preload on PHP 7.4+ */ public function warmUp(string $cacheDir) { @@ -61,12 +63,15 @@ public function warmUp(string $cacheDir) // so here we un-serialize the values first $values = array_map(function ($val) { return null !== $val ? unserialize($val) : null; }, $arrayAdapter->getValues()); - $this->warmUpPhpArrayAdapter(new PhpArrayAdapter($this->phpArrayFile, new NullAdapter()), $values); + return $this->warmUpPhpArrayAdapter(new PhpArrayAdapter($this->phpArrayFile, new NullAdapter()), $values); } + /** + * @return string[] A list of classes to preload on PHP 7.4+ + */ protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array $values) { - $phpArrayAdapter->warmUp($values); + return $phpArrayAdapter->warmUp($values); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/CachePoolClearerCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/CachePoolClearerCacheWarmer.php index 988181b7f8715..734ed5ffb6309 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/CachePoolClearerCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/CachePoolClearerCacheWarmer.php @@ -36,14 +36,18 @@ public function __construct(Psr6CacheClearer $poolClearer, array $pools = []) /** * {@inheritdoc} + * + * @return string[] */ - public function warmUp($cacheDirectory): void + public function warmUp($cacheDirectory): array { foreach ($this->pools as $pool) { if ($this->poolClearer->hasPool($pool)) { $this->poolClearer->clearPool($pool); } } + + return []; } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/RouterCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/RouterCacheWarmer.php index 6f90bba8b076c..5339db4b394ce 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/RouterCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/RouterCacheWarmer.php @@ -36,15 +36,15 @@ public function __construct(ContainerInterface $container) /** * {@inheritdoc} + * + * @return string[] */ public function warmUp(string $cacheDir) { $router = $this->container->get('router'); if ($router instanceof WarmableInterface) { - $router->warmUp($cacheDir); - - return; + return $router->warmUp($cacheDir); } throw new \LogicException(sprintf('The router "%s" cannot be warmed up because it does not implement "%s".', get_debug_type($router), WarmableInterface::class)); diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TranslationsCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TranslationsCacheWarmer.php index 28b6e439ab57c..9c94f16e674a7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TranslationsCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TranslationsCacheWarmer.php @@ -35,6 +35,8 @@ public function __construct(ContainerInterface $container) /** * {@inheritdoc} + * + * @return string[] */ public function warmUp(string $cacheDir) { @@ -43,8 +45,10 @@ public function warmUp(string $cacheDir) } if ($this->translator instanceof WarmableInterface) { - $this->translator->warmUp($cacheDir); + return $this->translator->warmUp($cacheDir); } + + return []; } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php index 8569521bc599b..89e9c1872a3d5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php @@ -68,10 +68,13 @@ protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter) return true; } + /** + * @return string[] A list of classes to preload on PHP 7.4+ + */ protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array $values) { // make sure we don't cache null values - parent::warmUpPhpArrayAdapter($phpArrayAdapter, array_filter($values)); + return parent::warmUpPhpArrayAdapter($phpArrayAdapter, array_filter($values)); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php index 75836ce0b7f37..f7ea3b3a09931 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -17,6 +17,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\DependencyInjection\Dumper\Preloader; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Filesystem; @@ -117,7 +118,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $warmer = $kernel->getContainer()->get('cache_warmer'); // non optional warmers already ran during container compilation $warmer->enableOnlyOptionalWarmers(); - $warmer->warmUp($realCacheDir); + $preload = (array) $warmer->warmUp($warmupDir); + Preloader::append($warmupDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php', $preload); } } else { $fs->mkdir($warmupDir); @@ -193,7 +195,8 @@ private function warmup(string $warmupDir, string $realCacheDir, bool $enableOpt $warmer = $kernel->getContainer()->get('cache_warmer'); // non optional warmers already ran during container compilation $warmer->enableOnlyOptionalWarmers(); - $warmer->warmUp($warmupDir); + $preload = (array) $warmer->warmUp($warmupDir); + Preloader::append($warmupDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php', $preload); } // fix references to cached files with the real cache directory name diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php index 5eb5903223089..038d8722b7ed5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php @@ -21,16 +21,11 @@ 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; use Symfony\Contracts\Service\ServiceSubscriberInterface; -// Help opcache.preload discover always-needed symbols -class_exists(RedirectableCompiledUrlMatcher::class); -class_exists(Route::class); - /** * This Router creates the Loader only when the cache is empty. * @@ -90,6 +85,8 @@ public function getRouteCollection() /** * {@inheritdoc} + * + * @return string[] A list of classes to preload on PHP 7.4+ */ public function warmUp(string $cacheDir) { @@ -101,6 +98,11 @@ public function warmUp(string $cacheDir) $this->getGenerator(); $this->setOption('cache_dir', $currentDir); + + return [ + $this->getOption('generator_class'), + $this->getOption('matcher_class'), + ]; } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php index 74675b2205300..8ae38fd392168 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php @@ -95,6 +95,8 @@ public function __construct(ContainerInterface $container, MessageFormatterInter /** * {@inheritdoc} + * + * @return string[] */ public function warmUp(string $cacheDir) { @@ -113,6 +115,8 @@ public function warmUp(string $cacheDir) $this->loadCatalogue($locale); } + + return []; } public function addResource(string $format, $resource, string $locale, string $domain = null) diff --git a/src/Symfony/Bundle/SecurityBundle/CacheWarmer/ExpressionCacheWarmer.php b/src/Symfony/Bundle/SecurityBundle/CacheWarmer/ExpressionCacheWarmer.php index c3126ae7dbb17..7e72f08b6040f 100644 --- a/src/Symfony/Bundle/SecurityBundle/CacheWarmer/ExpressionCacheWarmer.php +++ b/src/Symfony/Bundle/SecurityBundle/CacheWarmer/ExpressionCacheWarmer.php @@ -34,10 +34,15 @@ public function isOptional() return true; } + /** + * @return string[] + */ public function warmUp(string $cacheDir) { foreach ($this->expressions as $expression) { $this->expressionLanguage->parse($expression, ['token', 'user', 'object', 'subject', 'roles', 'request', 'trust_resolver']); } + + return []; } } diff --git a/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php b/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php index c5fb5c8fbefc8..2fc1d390b3647 100644 --- a/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php +++ b/src/Symfony/Bundle/TwigBundle/CacheWarmer/TemplateCacheWarmer.php @@ -37,6 +37,8 @@ public function __construct(ContainerInterface $container, iterable $iterator) /** * {@inheritdoc} + * + * @return string[] A list of template files to preload on PHP 7.4+ */ public function warmUp(string $cacheDir) { @@ -44,14 +46,22 @@ public function warmUp(string $cacheDir) $this->twig = $this->container->get('twig'); } + $files = []; + foreach ($this->iterator as $template) { try { - $this->twig->load($template); + $template = $this->twig->load($template); + + if (\is_callable([$template, 'unwrap'])) { + $files[] = (new \ReflectionClass($template->unwrap()))->getFileName(); + } } catch (Error $e) { // problem during compilation, give up // might be a syntax error or a non-Twig template } } + + return $files; } /** diff --git a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php index cccc608042eda..4ae303d0a8875 100644 --- a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php @@ -291,6 +291,8 @@ public function clear(string $prefix = '') * Store an array of cached values. * * @param array $values The cached values + * + * @return string[] A list of classes to preload on PHP 7.4+ */ public function warmUp(array $values) { @@ -314,6 +316,7 @@ public function warmUp(array $values) } } + $preload = []; $dumpedValues = ''; $dumpedMap = []; $dump = <<<'EOF' @@ -334,7 +337,7 @@ public function warmUp(array $values) $value = "'N;'"; } elseif (\is_object($value) || \is_array($value)) { try { - $value = VarExporter::export($value, $isStaticValue); + $value = VarExporter::export($value, $isStaticValue, $preload); } catch (\Exception $e) { throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, get_debug_type($value)), 0, $e); } @@ -376,6 +379,8 @@ public function warmUp(array $values) unset(self::$valuesCache[$this->file]); $this->initialize(); + + return $preload; } /** diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 0bacf3d561da7..85fc39e543797 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -7,6 +7,7 @@ CHANGELOG * added support to autowire public typed properties in php 7.4 * added support for defining method calls, a configurator, and property setters in `InlineServiceConfigurator` * added possibility to define abstract service arguments + * added class `Symfony\Component\DependencyInjection\Dumper\Preloader` to help with preloading on PHP 7.4+ 5.0.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php index abb7d90ff52bc..c2c460c89b530 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/Preloader.php @@ -13,12 +13,31 @@ /** * @author Nicolas Grekas - * - * @internal */ -class Preloader +final class Preloader { - public static function preload(array $classes) + public function append(string $file, array $list): void + { + if (!file_exists($file)) { + throw new \LogicException(sprintf('File "%s" does not exist.', $file)); + } + + $cacheDir = \dirname($file); + $classes = []; + + foreach ($list as $item) { + if (0 === strpos($item, $cacheDir)) { + file_put_contents($file, sprintf("require __DIR__.%s;\n", var_export(substr($item, \strlen($cacheDir)), true)), FILE_APPEND); + continue; + } + + $classes[] = sprintf("\$classes[] = %s;\n", var_export($item, true)); + } + + file_put_contents($file, sprintf("\n\$classes = [];\n%sPreloader::preload(\$classes);\n", implode($classes)), FILE_APPEND); + } + + public static function preload(array $classes): void { set_error_handler(function ($t, $m, $f, $l) { if (error_reporting() & $t) { diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index ada9fafe60102..23730cc31fddd 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -6,6 +6,8 @@ CHANGELOG * allowed using public aliases to reference controllers * added session usage reporting when the `_stateless` attribute of the request is set to `true` + * made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+; + not returning an array is deprecated 5.0.0 ----- diff --git a/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php b/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php index 1b3d73b7e16d5..bfaf76b81803c 100644 --- a/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php +++ b/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php @@ -45,6 +45,8 @@ public function enableOnlyOptionalWarmers() /** * Warms up the cache. + * + * @return string[] A list of classes or files to preload on PHP 7.4+ */ public function warmUp(string $cacheDir) { @@ -92,7 +94,7 @@ public function warmUp(string $cacheDir) continue; } - $warmer->warmUp($cacheDir); + $preload[] = array_values((array) $warmer->warmUp($cacheDir)); } } finally { if ($collectDeprecations) { @@ -106,6 +108,11 @@ public function warmUp(string $cacheDir) file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs))); } } + + $preload = array_merge([], ...$preload); + $preload = array_keys(array_flip($preload)); + + return $preload; } /** diff --git a/src/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php b/src/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php index e7715a33f6c99..2f442cb5368b4 100644 --- a/src/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php +++ b/src/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php @@ -20,6 +20,8 @@ interface WarmableInterface { /** * Warms up the cache. + * + * @return string[] A list of classes or files to preload on PHP 7.4+ */ public function warmUp(string $cacheDir); } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index ce3bd62408d3f..df0d47eafe581 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -22,6 +22,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; +use Symfony\Component\DependencyInjection\Dumper\Preloader; use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\Loader\DirectoryLoader; use Symfony\Component\DependencyInjection\Loader\GlobFileLoader; @@ -551,7 +552,11 @@ protected function initializeContainer() } if ($this->container->has('cache_warmer')) { - $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir')); + $preload = (array) $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir')); + + if (method_exists(Preloader::class, 'append')) { + Preloader::append($cacheDir.'/'.$class.'.preload.php', $preload); + } } } diff --git a/src/Symfony/Component/HttpKernel/Tests/CacheWarmer/CacheWarmerTest.php b/src/Symfony/Component/HttpKernel/Tests/CacheWarmer/CacheWarmerTest.php index 9cced03a471ea..eeb39e4dca678 100644 --- a/src/Symfony/Component/HttpKernel/Tests/CacheWarmer/CacheWarmerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/CacheWarmer/CacheWarmerTest.php @@ -54,9 +54,14 @@ public function __construct(string $file) $this->file = $file; } + /** + * @return string[] + */ public function warmUp(string $cacheDir) { $this->writeCacheFile($this->file, 'content'); + + return []; } public function isOptional(): bool diff --git a/src/Symfony/Component/Translation/DataCollectorTranslator.php b/src/Symfony/Component/Translation/DataCollectorTranslator.php index 2a5783c247269..386acf43c5139 100644 --- a/src/Symfony/Component/Translation/DataCollectorTranslator.php +++ b/src/Symfony/Component/Translation/DataCollectorTranslator.php @@ -81,12 +81,16 @@ public function getCatalogue(string $locale = null) /** * {@inheritdoc} + * + * @return string[] */ public function warmUp(string $cacheDir) { if ($this->translator instanceof WarmableInterface) { - $this->translator->warmUp($cacheDir); + return $this->translator->warmUp($cacheDir); } + + return []; } /** diff --git a/src/Symfony/Component/VarExporter/CHANGELOG.md b/src/Symfony/Component/VarExporter/CHANGELOG.md index 9aa4a8b3101d2..3406c30efb4bf 100644 --- a/src/Symfony/Component/VarExporter/CHANGELOG.md +++ b/src/Symfony/Component/VarExporter/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +5.1.0 +----- + + * added argument `array &$foundClasses` to `VarExporter::export()` to ease with preloading exported values + 4.2.0 ----- diff --git a/src/Symfony/Component/VarExporter/VarExporter.php b/src/Symfony/Component/VarExporter/VarExporter.php index da9a8d43736fa..9d70ac724b64b 100644 --- a/src/Symfony/Component/VarExporter/VarExporter.php +++ b/src/Symfony/Component/VarExporter/VarExporter.php @@ -34,12 +34,13 @@ final class VarExporter * * @param mixed $value The value to export * @param bool &$isStaticValue Set to true after execution if the provided value is static, false otherwise + * @param bool &$classes Classes found in the value are added to this list as both keys and values * * @return string The value exported as PHP code * * @throws ExceptionInterface When the provided value cannot be serialized */ - public static function export($value, bool &$isStaticValue = null): string + public static function export($value, bool &$isStaticValue = null, array &$foundClasses = []): string { $isStaticValue = true; @@ -71,7 +72,9 @@ public static function export($value, bool &$isStaticValue = null): string $values = []; $states = []; foreach ($objectsPool as $i => $v) { - list(, $classes[], $values[], $wakeup) = $objectsPool[$v]; + [, $class, $values[], $wakeup] = $objectsPool[$v]; + $foundClasses[$class] = $classes[] = $class; + if (0 < $wakeup) { $states[$wakeup] = $i; } elseif (0 > $wakeup) {