Skip to content

Commit 53f1a64

Browse files
xificurkclaude
andauthored
SymfonyContainerResultCacheMetaExtension optimization (#488)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5c0aafd commit 53f1a64

3 files changed

Lines changed: 116 additions & 1 deletion

File tree

extension.neon

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,5 +312,8 @@ services:
312312

313313
-
314314
class: PHPStan\Symfony\SymfonyContainerResultCacheMetaExtension
315+
arguments:
316+
tmpDir: %tmpDir%
317+
containerXmlPath: %symfony.containerXmlPath%
315318
tags:
316319
- phpstan.resultCacheMetaExtension

src/Symfony/SymfonyContainerResultCacheMetaExtension.php

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@
44

55
use PHPStan\Analyser\ResultCache\ResultCacheMetaExtension;
66
use function array_map;
7+
use function basename;
8+
use function file_get_contents;
9+
use function file_put_contents;
710
use function hash;
11+
use function hash_file;
812
use function ksort;
913
use function sort;
14+
use function sprintf;
1015
use function var_export;
1116

1217
final class SymfonyContainerResultCacheMetaExtension implements ResultCacheMetaExtension
@@ -16,10 +21,16 @@ final class SymfonyContainerResultCacheMetaExtension implements ResultCacheMetaE
1621

1722
private ServiceMap $serviceMap;
1823

19-
public function __construct(ParameterMap $parameterMap, ServiceMap $serviceMap)
24+
private string $tmpDir;
25+
26+
private ?string $containerXmlPath;
27+
28+
public function __construct(ParameterMap $parameterMap, ServiceMap $serviceMap, string $tmpDir, ?string $containerXmlPath)
2029
{
2130
$this->parameterMap = $parameterMap;
2231
$this->serviceMap = $serviceMap;
32+
$this->tmpDir = $tmpDir;
33+
$this->containerXmlPath = $containerXmlPath;
2334
}
2435

2536
public function getKey(): string
@@ -28,6 +39,33 @@ public function getKey(): string
2839
}
2940

3041
public function getHash(): string
42+
{
43+
if ($this->containerXmlPath !== null) {
44+
$xmlHash = hash_file('sha256', $this->containerXmlPath);
45+
if ($xmlHash === false) {
46+
throw new XmlContainerNotExistsException(sprintf('Container %s does not exist', $this->containerXmlPath));
47+
}
48+
$xmlHashFile = sprintf('%s/%s-%s.hash', $this->tmpDir, $this->getKey(), basename($this->containerXmlPath));
49+
$storedXmlHash = @file_get_contents($xmlHashFile);
50+
51+
$hashForResultCacheFile = sprintf('%s/%s-%s-result-cache-meta.hash', $this->tmpDir, $this->getKey(), basename($this->containerXmlPath));
52+
$storedHashForResultCache = @file_get_contents($hashForResultCacheFile);
53+
if ($storedXmlHash === $xmlHash && $storedHashForResultCache !== false) {
54+
return $storedHashForResultCache;
55+
}
56+
}
57+
58+
$hashForResultCache = $this->calculateHash();
59+
60+
if ($this->containerXmlPath !== null) {
61+
file_put_contents($hashForResultCacheFile, $hashForResultCache);
62+
file_put_contents($xmlHashFile, $xmlHash);
63+
}
64+
65+
return $hashForResultCache;
66+
}
67+
68+
private function calculateHash(): string
3169
{
3270
$services = $parameters = [];
3371

tests/Symfony/SymfonyContainerResultCacheMetaExtensionTest.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,83 @@
44

55
use PHPStan\Testing\PHPStanTestCase;
66
use function count;
7+
use function file_get_contents;
8+
use function file_put_contents;
9+
use function glob;
10+
use function mkdir;
11+
use function rmdir;
12+
use function sprintf;
13+
use function sys_get_temp_dir;
14+
use function uniqid;
15+
use function unlink;
716

817
/**
918
* @phpstan-type ContainerContents array{parameters?: ParameterMap, services?: ServiceMap}
1019
*/
1120
final class SymfonyContainerResultCacheMetaExtensionTest extends PHPStanTestCase
1221
{
1322

23+
private string $tmpDir;
24+
25+
protected function setUp(): void
26+
{
27+
parent::setUp();
28+
$this->tmpDir = sys_get_temp_dir() . '/phpstan-symfony-test-' . uniqid('', true);
29+
mkdir($this->tmpDir, 0777, true);
30+
}
31+
32+
protected function tearDown(): void
33+
{
34+
$cacheFiles = glob($this->tmpDir . '/*.hash');
35+
if ($cacheFiles !== false) {
36+
foreach ($cacheFiles as $file) {
37+
unlink($file);
38+
}
39+
}
40+
rmdir($this->tmpDir);
41+
parent::tearDown();
42+
}
43+
44+
public function testHashIsCalculatedAndWrittenToCacheFileOnCacheMiss(): void
45+
{
46+
$containerXmlPath = __DIR__ . '/container.xml';
47+
48+
$extension = new SymfonyContainerResultCacheMetaExtension(
49+
new DefaultParameterMap([]),
50+
new DefaultServiceMap([]),
51+
$this->tmpDir,
52+
$containerXmlPath,
53+
);
54+
55+
$hash = $extension->getHash();
56+
57+
$resultCacheHashFile = sprintf('%s/symfonyDiContainer-container.xml-result-cache-meta.hash', $this->tmpDir);
58+
self::assertFileExists($resultCacheHashFile);
59+
self::assertSame($hash, file_get_contents($resultCacheHashFile));
60+
61+
$xmlHashFile = sprintf('%s/symfonyDiContainer-container.xml.hash', $this->tmpDir);
62+
self::assertFileExists($xmlHashFile);
63+
self::assertSame('c55d6ac45b535d6ecc9402cbb93825c38ec7b11b03f66577d0d3549b3d9ef75f', file_get_contents($xmlHashFile));
64+
}
65+
66+
public function testCachedHashIsReturnedOnCacheHit(): void
67+
{
68+
$containerXmlPath = __DIR__ . '/container.xml';
69+
$xmlHashFile = sprintf('%s/symfonyDiContainer-container.xml.hash', $this->tmpDir);
70+
file_put_contents($xmlHashFile, 'c55d6ac45b535d6ecc9402cbb93825c38ec7b11b03f66577d0d3549b3d9ef75f');
71+
$resultCacheHashFile = sprintf('%s/symfonyDiContainer-container.xml-result-cache-meta.hash', $this->tmpDir);
72+
file_put_contents($resultCacheHashFile, 'pre-computed-hash');
73+
74+
$extension = new SymfonyContainerResultCacheMetaExtension(
75+
new DefaultParameterMap([]),
76+
new DefaultServiceMap([]),
77+
$this->tmpDir,
78+
$containerXmlPath,
79+
);
80+
81+
self::assertSame('pre-computed-hash', $extension->getHash());
82+
}
83+
1484
/**
1585
* @param list<ContainerContents> $sameHashContents
1686
* @param ContainerContents $invalidatingContent
@@ -30,6 +100,8 @@ public function testContainerHashIsCalculatedCorrectly(
30100
$currentHash = (new SymfonyContainerResultCacheMetaExtension(
31101
$content['parameters'] ?? new DefaultParameterMap([]),
32102
$content['services'] ?? new DefaultServiceMap([]),
103+
__DIR__ . '/../../tmp',
104+
null,
33105
))->getHash();
34106

35107
if ($hash === null) {
@@ -44,6 +116,8 @@ public function testContainerHashIsCalculatedCorrectly(
44116
(new SymfonyContainerResultCacheMetaExtension(
45117
$invalidatingContent['parameters'] ?? new DefaultParameterMap([]),
46118
$invalidatingContent['services'] ?? new DefaultServiceMap([]),
119+
__DIR__ . '/../../tmp',
120+
null,
47121
))->getHash(),
48122
);
49123
}

0 commit comments

Comments
 (0)