Skip to content
Merged
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
11 changes: 9 additions & 2 deletions src/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ class ContainerBuilder
*/
private $sourceCache = false;

/**
* @var string
*/
protected $sourceCacheNamespace;

/**
* Build a container configured for the dev environment.
*/
Expand Down Expand Up @@ -155,7 +160,7 @@ public function build()
throw new \Exception('APCu is not enabled, PHP-DI cannot use it as a cache');
}
// Wrap the source with the cache decorator
$source = new SourceCache($source);
$source = new SourceCache($source, $this->sourceCacheNamespace);
}

$proxyFactory = new ProxyFactory(
Expand Down Expand Up @@ -350,13 +355,15 @@ public function addDefinitions(...$definitions) : self
*
* @see http://php-di.org/doc/performances.html
*
* @param string $cacheNamespace use unique namespace per container when sharing a single APC memory pool to prevent cache collisions
* @return $this
*/
public function enableDefinitionCache() : self
public function enableDefinitionCache(string $cacheNamespace = '') : self
{
$this->ensureNotLocked();

$this->sourceCache = true;
$this->sourceCacheNamespace = $cacheNamespace;

return $this;
}
Expand Down
17 changes: 14 additions & 3 deletions src/Definition/Source/SourceCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,27 @@ class SourceCache implements DefinitionSource, MutableDefinitionSource
*/
private $cachedSource;

public function __construct(DefinitionSource $cachedSource)
/**
* @var string
*/
private $cacheNamespace;

public function __construct(DefinitionSource $cachedSource, string $cacheNamespace = '')
{
$this->cachedSource = $cachedSource;
$this->cacheNamespace = $cacheNamespace;
}

public function getDefinition(string $name)
{
$definition = apcu_fetch(self::CACHE_KEY . $name);
$definition = apcu_fetch($this->getCacheKey($name));

if ($definition === false) {
$definition = $this->cachedSource->getDefinition($name);

// Update the cache
if ($this->shouldBeCached($definition)) {
apcu_store(self::CACHE_KEY . $name, $definition);
apcu_store($this->getCacheKey($name), $definition);
}
}

Expand All @@ -59,6 +65,11 @@ public static function isSupported() : bool
&& ! ('cli' === \PHP_SAPI && ! ini_get('apc.enable_cli'));
}

public function getCacheKey(string $name) : string
{
return self::CACHE_KEY . $this->cacheNamespace . $name;
}

public function addDefinition(Definition $definition)
{
throw new \LogicException('You cannot set a definition at runtime on a container that has caching enabled. Doing so would risk caching the definition for the next execution, where it might be different. You can either put your definitions in a file, remove the cache or ->set() a raw value directly (PHP object, string, int, ...) instead of a PHP-DI definition.');
Expand Down
22 changes: 22 additions & 0 deletions tests/UnitTest/ContainerBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,28 @@ public function should_allow_to_configure_a_cache()
$this->assertInstanceOf(SourceCache::class, $container->definitionSource);
}

/**
* @test
*/
public function should_allow_to_configure_a_cache_with_a_namespace()
{
if (! SourceCache::isSupported()) {
$this->markTestSkipped('APCu extension is required');
return;
}

$namespace = 'staging';
$builder = new ContainerBuilder(FakeContainer::class);
$builder->enableDefinitionCache($namespace);

/** @var FakeContainer $container */
$container = $builder->build();
$source = $container->definitionSource;

$this->assertInstanceOf(SourceCache::class, $source);
$this->assertSame($source->getCacheKey('foo'), SourceCache::CACHE_KEY . $namespace . 'foo');
}

/**
* @test
*/
Expand Down
10 changes: 10 additions & 0 deletions tests/UnitTest/Definition/Source/SourceCacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ public function should_only_cache_object_and_autowire_definitions()
self::assertSame($definition, $source->getDefinition('foo'));
}

/**
* @test
*/
public function should_use_namespaced_cache_keys()
{
$namespace = 'staging';
$source = new SourceCache(new DefinitionArray, $namespace);
self::assertSame($source->getCacheKey('foo'), SourceCache::CACHE_KEY . $namespace . 'foo');
}

private static function assertSavedInCache(string $definitionName, $expectedValue)
{
$definition = apcu_fetch(SourceCache::CACHE_KEY . $definitionName);
Expand Down