8000 [ClassLoader] Add ClassCollectionLoader::inline() to generate inlined-classes files by nicolas-grekas · Pull Request #19276 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[ClassLoader] Add ClassCollectionLoader::inline() to generate inlined-classes files #19276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
*/
class ClassCacheCacheWarmer implements CacheWarmerInterface
{
private $declaredClasses;

public function __construct(array $declaredClasses = null)
{
$this->declaredClasses = $declaredClasses;
}

/**
* Warms up the cache.
*
Expand All @@ -37,8 +44,9 @@ public function warmUp($cacheDir)
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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,23 @@ public function load(array $configs, ContainerBuilder $container)
}

$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',
Expand All @@ -189,13 +197,18 @@ public function load(array $configs, ContainerBuilder $container)
'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',
));
}

Expand Down
11 changes: 11 additions & 0 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@

<service id="kernel.class_cache.cache_warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\ClassCacheCacheWarmer">
<tag name="kernel.cache_warmer" />
<argument type="collection">
<argument>Doctrine\Common\Annotations\AnnotationRegistry</argument>
<argument>Symfony\Component\HttpFoundation\ParameterBag</argument>
<argument>Symfony\Component\HttpFoundation\HeaderBag</argument>
<argument>Symfony\Component\HttpFoundation\FileBag</argument>
<argument>Symfony\Component\HttpFoundation\ServerBag</argument>
<argument>Symfony\Component\HttpFoundation\Request</argument>
<argument>Symfony\Component\HttpKernel\Kernel</argument>
<argument>Symfony\Component\ClassLoader\ClassCollectionLoader</argument>
<argument>Symfony\Component\ClassLoader\ApcClassLoader</argument>
</argument>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fragile. We should have tests to ensure that we don't break this at some point.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll see what can do. Btw, would it make sense to move the composer script from distributionbundle to frameworkbundle?

Copy link
Member Author
@nicolas-grekas nicolas-grekas Jul 10, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, what about moving this list in distributionbundle? => not possible, the bundle is not enabled in prod env

</service>

<service id="cache_clearer" class="Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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('<?php return %s;', var_export(array(WarmedClass::class), true)));

$warmer = new ClassCacheCacheWarmer(array(DeclaredClass::class));

$warmer->warmUp($dir);

$this->assertSame(<<<'EOTXT'
<?php
namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures
{
class WarmedClass extends DeclaredClass
{
}
}
EOTXT
, file_get_contents($dir.'/classes.php')
);

@unlink($dir.'/classes.map');
@unlink($dir.'/classes.php');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures;

class DeclaredClass
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures;

class WarmedClass extends DeclaredClass
{
}
2 changes: 1 addition & 1 deletion src/Symfony/Bundle/FrameworkBundle/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"php": ">=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",
Expand Down
37 changes: 31 additions & 6 deletions src/Symfony/Component/ClassLoader/ClassCollectionLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,41 @@ public static function load($classes, $cacheDir, $name, $autoReload, $adaptive =
$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()));

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

// 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, '<?php '.$content);

if ($autoReload) {
// save the resources
self::writeCacheFile($metadata, serialize(array($files, $classes)));
}
return $files;
}

/**
Expand Down < 10000 /td>
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
namespace Symfony\Component\ClassLoader\Tests;

use Symfony\Component\ClassLoader\ClassCollectionLoader;
use Symfony\Component\ClassLoader\Tests\Fixtures\DeclaredClass;
use Symfony\Component\ClassLoader\Tests\Fixtures\WarmedClass;

require_once __DIR__.'/Fixtures/ClassesWithParents/GInterface.php';
require_once __DIR__.'/Fixtures/ClassesWithParents/CInterface.php';
Expand Down Expand Up @@ -271,4 +273,36 @@ class Pearlike_WithComments

unlink($file);
}

public function testInline()
{
$this->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'
<?php
namespace Symfony\Component\ClassLoader\Tests\Fixtures
{
interface WarmedInterface
{
}
}
namespace Symfony\Component\ClassLoader\Tests\Fixtures
{
class WarmedClass extends DeclaredClass implements WarmedInterface
{
}
}
EOTXT
, file_get_contents($cache)
);

unlink($cache);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Symfony\Component\ClassLoader\Tests\Fixtures;

class DeclaredClass implements DeclaredInterface
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Symfony\Component\ClassLoader\Tests\Fixtures;

interface DeclaredInterface
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Symfony\Component\ClassLoader\Tests\Fixtures;

class WarmedClass extends DeclaredClass implements WarmedInterface
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Symfony\Component\ClassLoader\Tests\Fixtures;

interface WarmedInterface
{
}
0