From 88fdceadd49de61e7cf12eb976d82edf05350fbe Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 3 Jul 2016 11:23:01 +0200 Subject: [PATCH] [ClassLoader] Add ClassCollectionLoader::inline() to generate inlined-classes files --- .../CacheWarmer/ClassCacheCacheWarmer.php | 10 +++- .../FrameworkExtension.php | 13 +++++ .../Resources/config/services.xml | 11 +++++ .../CacheWarmer/ClassCacheCacheWarmerTest.php | 48 +++++++++++++++++++ .../Tests/Fixtures/DeclaredClass.php | 7 +++ .../Tests/Fixtures/WarmedClass.php | 7 +++ .../Bundle/FrameworkBundle/composer.json | 2 +- .../ClassLoader/ClassCollectionLoader.php | 37 +++++++++++--- .../Tests/ClassCollectionLoaderTest.php | 34 +++++++++++++ .../Tests/Fixtures/DeclaredClass.php | 7 +++ .../Tests/Fixtures/DeclaredInterface.php | 7 +++ .../Tests/Fixtures/WarmedClass.php | 7 +++ .../Tests/Fixtures/WarmedInterface.php | 7 +++ 13 files changed, 189 insertions(+), 8 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ClassCacheCacheWarmerTest.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/DeclaredClass.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/WarmedClass.php create mode 100644 src/Symfony/Component/ClassLoader/Tests/Fixtures/DeclaredClass.php create mode 100644 src/Symfony/Component/ClassLoader/Tests/Fixtures/DeclaredInterface.php create mode 100644 src/Symfony/Component/ClassLoader/Tests/Fixtures/WarmedClass.php create mode 100644 src/Symfony/Component/ClassLoader/Tests/Fixtures/WarmedInterface.php diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ClassCacheCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ClassCacheCacheWarmer.php index 54b9b3395e..b235c65136 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ClassCacheCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ClassCacheCacheWarmer.php @@ -21,6 +21,13 @@ use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; */ class ClassCacheCacheWarmer implements CacheWarmerInterface { + private $declaredClasses; + + public function __construct(array $declaredClasses = null) + { + $this->declaredClasses = $declaredClasses; + } + /** * Warms up the cache. * @@ -37,8 +44,9 @@ class ClassCacheCacheWarmer implements CacheWarmerInterface if (file_exists($cacheDir.'/classes.php')) { return; } + $declared = null !== $this->declaredClasses ? $this->declaredClasses : array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits()); - ClassCollectionLoader::load(include($classmap), $cacheDir, 'classes', false); + ClassCollectionLoader::inline(include($classmap), $cacheDir.'/classes.php', $declared); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 8cd1fea64a..d0751c095d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -170,15 +170,23 @@ class FrameworkExtension extends Extension } $this->addClassesToCompile(array( + 'Symfony\\Component\\Config\\ConfigCache', 'Symfony\\Component\\Config\\FileLocator', 'Symfony\\Component\\Debug\\ErrorHandler', + 'Symfony\\Component\\DependencyInjection\\ContainerAwareInterface', + 'Symfony\\Component\\DependencyInjection\\Container', + 'Symfony\\Component\\EventDispatcher\\Event', 'Symfony\\Component\\EventDispatcher\\ContainerAwareEventDispatcher', + 'Symfony\\Component\\HttpFoundation\\Response', + 'Symfony\\Component\\HttpFoundation\\ResponseHeaderBag', + 'Symfony\\Component\\HttpKernel\\EventListener\\ResponseListener', 'Symfony\\Component\\HttpKernel\\EventListener\\RouterListener', + 'Symfony\\Component\\HttpKernel\\Bundle\\Bundle', 'Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver', 'Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver', 'Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata', @@ -189,13 +197,18 @@ class FrameworkExtension extends Extension 'Symfony\\Component\\HttpKernel\\Event\\GetResponseEvent', 'Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent', 'Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent', + 'Symfony\\Component\\HttpKernel\\HttpKernel', 'Symfony\\Component\\HttpKernel\\KernelEvents', 'Symfony\\Component\\HttpKernel\\Config\\FileLocator', 'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerNameParser', 'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver', + // Cannot be included because annotations will parse the big compiled class file // 'Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller', + + // cannot be included as commands are discovered based on the path to this class via Reflection + // 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle', )); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml index a5c0baba1b..71acb1bca2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml @@ -24,6 +24,17 @@ + + Doctrine\Common\Annotations\AnnotationRegistry + Symfony\Component\HttpFoundation\ParameterBag + Symfony\Component\HttpFoundation\HeaderBag + Symfony\Component\HttpFoundation\FileBag + Symfony\Component\HttpFoundation\ServerBag + Symfony\Component\HttpFoundation\Request + Symfony\Component\HttpKernel\Kernel + Symfony\Component\ClassLoader\ClassCollectionLoader + Symfony\Component\ClassLoader\ApcClassLoader + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ClassCacheCacheWarmerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ClassCacheCacheWarmerTest.php new file mode 100644 index 0000000000..889601b01f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/ClassCacheCacheWarmerTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\CacheWarmer; + +use Symfony\Bundle\FrameworkBundle\CacheWarmer\ClassCacheCacheWarmer; +use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\DeclaredClass; +use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\WarmedClass; +use Symfony\Bundle\FrameworkBundle\Tests\TestCase; + +class ClassCacheCacheWarmerTest extends TestCase +{ + public function testWithDeclaredClasses() + { + $this->assertTrue(class_exists(WarmedClass::class, true)); + + $dir = sys_get_temp_dir(); + @unlink($dir.'/classes.php'); + file_put_contents($dir.'/classes.map', sprintf('warmUp($dir); + + $this->assertSame(<<<'EOTXT' +=5.5.9", "symfony/asset": "~2.8|~3.0", "symfony/cache": "~3.1", - "symfony/class-loader": "~2.8|~3.0", + "symfony/class-loader": "~3.2", "symfony/dependency-injection": "~3.2", "symfony/config": "~2.8|~3.0", "symfony/event-dispatcher": "~2.8|~3.0", diff --git a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php index 3ec68c6b5e..3f7b4a639c 100644 --- a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php +++ b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php @@ -93,14 +93,41 @@ class ClassCollectionLoader $declared = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits()); } + $files = self::inline($classes, $cache, $declared); + + if ($autoReload) { + // save the resources + self::writeCacheFile($metadata, serialize(array(array_values($files), $classes))); + } + } + + /** + * Generates a file where classes and their parents are inlined. + * + * @param array $classes An array of classes to load + * @param string $cache The file where classes are inlined + * @param array $excluded An array of classes that won't be inlined + * + * @return array The source map of inlined classes, with classes as keys and files as values + * + * @throws \RuntimeException When class can't be loaded + */ + public static function inline($classes, $cache, array $excluded) + { + $declared = array(); + foreach (self::getOrderedClasses($excluded) as $class) { + $declared[$class->getName()] = true; + } + $files = array(); $content = ''; foreach (self::getOrderedClasses($classes) as $class) { - if (in_array($class->getName(), $declared)) { + if (isset($declared[$class->getName()])) { continue; } + $declared[$class->getName()] = true; - $files[] = $class->getFileName(); + $files[$class->getName()] = $class->getFileName(); $c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($class->getFileName())); @@ -116,15 +143,13 @@ class ClassCollectionLoader } // cache the core classes + $cacheDir = dirname($cache); if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) { throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir)); } self::writeCacheFile($cache, 'assertTrue(class_exists(WarmedClass::class, true)); + + @unlink($cache = sys_get_temp_dir().'/inline.php'); + + $classes = array(WarmedClass::class); + $excluded = array(DeclaredClass::class); + + ClassCollectionLoader::inline($classes, $cache, $excluded); + + $this->assertSame(<<<'EOTXT' +