Skip to content

Commit 88fdcea

Browse files
nicolas-grekasfabpot
authored andcommitted
[ClassLoader] Add ClassCollectionLoader::inline() to generate inlined-classes files
1 parent 36ec085 commit 88fdcea

File tree

13 files changed

+189
-8
lines changed

13 files changed

+189
-8
lines changed

src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ClassCacheCacheWarmer.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121
*/
2222
class ClassCacheCacheWarmer implements CacheWarmerInterface
2323
{
24+
private $declaredClasses;
25+
26+
public function __construct(array $declaredClasses = null)
27+
{
28+
$this->declaredClasses = $declaredClasses;
29+
}
30+
2431
/**
2532
* Warms up the cache.
2633
*
@@ -37,8 +44,9 @@ public function warmUp($cacheDir)
3744
if (file_exists($cacheDir.'/classes.php')) {
3845
return;
3946
}
47+
$declared = null !== $this->declaredClasses ? $this->declaredClasses : array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
4048

41-
ClassCollectionLoader::load(include($classmap), $cacheDir, 'classes', false);
49+
ClassCollectionLoader::inline(include($classmap), $cacheDir.'/classes.php', $declared);
4250
}
4351

4452
/**

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,15 +170,23 @@ public function load(array $configs, ContainerBuilder $container)
170170
}
171171

172172
$this->addClassesToCompile(array(
173+
'Symfony\\Component\\Config\\ConfigCache',
173174
'Symfony\\Component\\Config\\FileLocator',
174175

175176
'Symfony\\Component\\Debug\\ErrorHandler',
176177

178+
'Symfony\\Component\\DependencyInjection\\ContainerAwareInterface',
179+
'Symfony\\Component\\DependencyInjection\\Container',
180+
177181
'Symfony\\Component\\EventDispatcher\\Event',
178182
'Symfony\\Component\\EventDispatcher\\ContainerAwareEventDispatcher',
179183

184+
'Symfony\\Component\\HttpFoundation\\Response',
185+
'Symfony\\Component\\HttpFoundation\\ResponseHeaderBag',
186+
180187
'Symfony\\Component\\HttpKernel\\EventListener\\ResponseListener',
181188
'Symfony\\Component\\HttpKernel\\EventListener\\RouterListener',
189+
'Symfony\\Component\\HttpKernel\\Bundle\\Bundle',
182190
'Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver',
183191
'Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver',
184192
'Symfony\\Component\\HttpKernel\\ControllerMetadata\\ArgumentMetadata',
@@ -189,13 +197,18 @@ public function load(array $configs, ContainerBuilder $container)
189197
'Symfony\\Component\\HttpKernel\\Event\\GetResponseEvent',
190198
'Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent',
191199
'Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent',
200+
'Symfony\\Component\\HttpKernel\\HttpKernel',
192201
'Symfony\\Component\\HttpKernel\\KernelEvents',
193202
'Symfony\\Component\\HttpKernel\\Config\\FileLocator',
194203

195204
'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerNameParser',
196205
'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver',
206+
197207
// Cannot be included because annotations will parse the big compiled class file
198208
// 'Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller',
209+
210+
// cannot be included as commands are discovered based on the path to this class via Reflection
211+
// 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle',
199212
));
200213
}
201214

src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@
2424

2525
<service id="kernel.class_cache.cache_warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\ClassCacheCacheWarmer">
2626
<tag name="kernel.cache_warmer" />
27+
<argument type="collection">
28+
<argument>Doctrine\Common\Annotations\AnnotationRegistry</argument>
29+
<argument>Symfony\Component\HttpFoundation\ParameterBag</argument>
30+
<argument>Symfony\Component\HttpFoundation\HeaderBag</argument>
31+
<argument>Symfony\Component\HttpFoundation\FileBag</argument>
32+
<argument>Symfony\Component\HttpFoundation\ServerBag</argument>
33+
<argument>Symfony\Component\HttpFoundation\Request</argument>
34+
<argument>Symfony\Component\HttpKernel\Kernel</argument>
35+
<argument>Symfony\Component\ClassLoader\ClassCollectionLoader</argument>
36+
<argument>Symfony\Component\ClassLoader\ApcClassLoader</argument>
37+
</argument>
2738
</service>
2839

2940
<service id="cache_clearer" class="Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer">
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\CacheWarmer;
13+
14+
use Symfony\Bundle\FrameworkBundle\CacheWarmer\ClassCacheCacheWarmer;
15+
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\DeclaredClass;
16+
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\WarmedClass;
17+
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
18+
19+
class ClassCacheCacheWarmerTest extends TestCase
20+
{
21+
public function testWithDeclaredClasses()
22+
{
23+
$this->assertTrue(class_exists(WarmedClass::class, true));
24+
25+
$dir = sys_get_temp_dir();
26+
@unlink($dir.'/classes.php');
27+
file_put_contents($dir.'/classes.map', sprintf('<?php return %s;', var_export(array(WarmedClass::class), true)));
28+
29+
$warmer = new ClassCacheCacheWarmer(array(DeclaredClass::class));
30+
31+
$warmer->warmUp($dir);
32+
33+
$this->assertSame(<<<'EOTXT'
34+
<?php
35+
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures
36+
{
37+
class WarmedClass extends DeclaredClass
38+
{
39+
}
40+
}
41+
EOTXT
42+
, file_get_contents($dir.'/classes.php')
43+
);
44+
45+
@unlink($dir.'/classes.map');
46+
@unlink($dir.'/classes.php');
47+
}
48+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures;
4+
5+
class DeclaredClass
6+
{
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures;
4+
5+
class WarmedClass extends DeclaredClass
6+
{
7+
}

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"php": ">=5.5.9",
2020
"symfony/asset": "~2.8|~3.0",
2121
"symfony/cache": "~3.1",
22-
"symfony/class-loader": "~2.8|~3.0",
22+
"symfony/class-loader": "~3.2",
2323
"symfony/dependency-injection": "~3.2",
2424
"symfony/config": "~2.8|~3.0",
2525
"symfony/event-dispatcher": "~2.8|~3.0",

src/Symfony/Component/ClassLoader/ClassCollectionLoader.php

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,41 @@ public static function load($classes, $cacheDir, $name, $autoReload, $adaptive =
9393
$declared = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
9494
}
9595

96+
$files = self::inline($classes, $cache, $declared);
97+
98+
if ($autoReload) {
99+
// save the resources
100+
self::writeCacheFile($metadata, serialize(array(array_values($files), $classes)));
101+
}
102+
}
103+
104+
/**
105+
* Generates a file where classes and their parents are inlined.
106+
*
107+
* @param array $classes An array of classes to load
108+
* @param string $cache The file where classes are inlined
109+
* @param array $excluded An array of classes that won't be inlined
110+
*
111+
* @return array The source map of inlined classes, with classes as keys and files as values
112+
*
113+
* @throws \RuntimeException When class can't be loaded
114+
*/
115+
public static function inline($classes, $cache, array $excluded)
116+
{
117+
$declared = array();
118+
foreach (self::getOrderedClasses($excluded) as $class) {
119+
$declared[$class->getName()] = true;
120+
}
121+
96122
$files = array();
97123
$content = '';
98124
foreach (self::getOrderedClasses($classes) as $class) {
99-
if (in_array($class->getName(), $declared)) {
125+
if (isset($declared[$class->getName()])) {
100126
continue;
101127
}
128+
$declared[$class->getName()] = true;
102129

103-
$files[] = $class->getFileName();
130+
$files[$class->getName()] = $class->getFileName();
104131

105132
$c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($class->getFileName()));
106133

@@ -116,15 +143,13 @@ public static function load($classes, $cacheDir, $name, $autoReload, $adaptive =
116143
}
117144

118145
// cache the core classes
146+
$cacheDir = dirname($cache);
119147
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
120148
throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir));
121149
}
122150
self::writeCacheFile($cache, '<?php '.$content);
123151

124-
if ($autoReload) {
125-
// save the resources
126-
self::writeCacheFile($metadata, serialize(array($files, $classes)));
127-
}
152+
return $files;
128153
}
129154

130155
/**

src/Symfony/Component/ClassLoader/Tests/ClassCollectionLoaderTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace Symfony\Component\ClassLoader\Tests;
1313

1414
use Symfony\Component\ClassLoader\ClassCollectionLoader;
15+
use Symfony\Component\ClassLoader\Tests\Fixtures\DeclaredClass;
16+
use Symfony\Component\ClassLoader\Tests\Fixtures\WarmedClass;
1517

1618
require_once __DIR__.'/Fixtures/ClassesWithParents/GInterface.php';
1719
require_once __DIR__.'/Fixtures/ClassesWithParents/CInterface.php';
@@ -271,4 +273,36 @@ class Pearlike_WithComments
271273

272274
unlink($file);
273275
}
276+
277+
public function testInline()
278+
{
279+
$this->assertTrue(class_exists(WarmedClass::class, true));
280+
281+
@unlink($cache = sys_get_temp_dir().'/inline.php');
282+
283+
$classes = array(WarmedClass::class);
284+
$excluded = array(DeclaredClass::class);
285+
286+
ClassCollectionLoader::inline($classes, $cache, $excluded);
287+
288+
$this->assertSame(<<<'EOTXT'
289+
<?php
290+
namespace Symfony\Component\ClassLoader\Tests\Fixtures
291+
{
292+
interface WarmedInterface
293+
{
294+
}
295+
}
296+
namespace Symfony\Component\ClassLoader\Tests\Fixtures
297+
{
298+
class WarmedClass extends DeclaredClass implements WarmedInterface
299+
{
300+
}
301+
}
302+
EOTXT
303+
, file_get_contents($cache)
304+
);
305+
306+
unlink($cache);
307+
}
274308
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Symfony\Component\ClassLoader\Tests\Fixtures;
4+
5+
class DeclaredClass implements DeclaredInterface
6+
{
7+
}

0 commit comments

Comments
 (0)