Skip to content

Commit 4bde072

Browse files
committed
Initial implementation of ResultCacheMetaExtension
This introduces contract for extending the way how result cache metadata is calculated, so PHPStan extensions can take part into deciding whether analysis should be re-run or its result can be re-use from cache.
1 parent af1722d commit 4bde072

File tree

3 files changed

+72
-0
lines changed

3 files changed

+72
-0
lines changed

src/Analyser/ResultCache/ResultCacheManager.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PHPStan\Command\Output;
1111
use PHPStan\Dependency\ExportedNodeFetcher;
1212
use PHPStan\Dependency\RootExportedNode;
13+
use PHPStan\DependencyInjection\Container;
1314
use PHPStan\DependencyInjection\ProjectConfigHelper;
1415
use PHPStan\File\CouldNotReadFileException;
1516
use PHPStan\File\FileFinder;
@@ -66,6 +67,7 @@ final class ResultCacheManager
6667
* @param string[] $scanDirectories
6768
*/
6869
public function __construct(
70+
private Container $container,
6971
private ExportedNodeFetcher $exportedNodeFetcher,
7072
private FileFinder $scanFileFinder,
7173
private ReflectionProvider $reflectionProvider,
@@ -317,6 +319,11 @@ private function isMetaDifferent(array $cachedMeta, array $currentMeta): bool
317319
$currentMeta['projectConfig'] = Neon::encode($currentMeta['projectConfig']);
318320
}
319321

322+
// Do not invalidate result cache generated before introducing support for result cache meta extensions
323+
if (!isset($currentMeta['phpstanExtensions'])) {
324+
$currentMeta['phpstanExtensions'] = [];
325+
}
326+
320327
return $cachedMeta !== $currentMeta;
321328
}
322329

@@ -904,6 +911,7 @@ private function getMeta(array $allAnalysedFiles, ?array $projectConfigArray): a
904911
return [
905912
'cacheVersion' => self::CACHE_VERSION,
906913
'phpstanVersion' => ComposerHelper::getPhpStanVersion(),
914+
'phpstanExtensions' => $this->getMetaFromPhpStanExtensions(),
907915
'phpVersion' => PHP_VERSION_ID,
908916
'projectConfig' => $projectConfigArray,
909917
'analysedPaths' => $this->analysedPaths,
@@ -1036,4 +1044,27 @@ private function getStubFiles(): array
10361044
return $stubFiles;
10371045
}
10381046

1047+
/**
1048+
* @return array<string, string>
1049+
* @throws ShouldNotHappenException
1050+
*/
1051+
private function getMetaFromPhpStanExtensions(): array
1052+
{
1053+
$meta = [];
1054+
1055+
/** @var ResultCacheMetaExtension $extension */
1056+
foreach ($this->container->getServicesByTag(ResultCacheMetaExtension::EXTENSION_TAG) as $extension) {
1057+
if (array_key_exists($extension->getKey(), $meta)) {
1058+
throw new ShouldNotHappenException(sprintf(
1059+
'Duplicate ResultCacheMetaExtension with key "%s" found.',
1060+
$extension->getKey(),
1061+
));
1062+
}
1063+
1064+
$meta[$extension->getKey()] = $extension->getHash();
1065+
}
1066+
1067+
return $meta;
1068+
}
1069+
10391070
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser\ResultCache;
4+
5+
/**
6+
* ResultCacheMetaExtension can be used for extending PHPStan's built-in mechanism that is used for
7+
* calculating metadata for result cache. Using this extension you may add additional metadata that will
8+
* be used for determining if analysis must be run again, or can be re-used from result cache.
9+
*
10+
* @see https://github.com/phpstan/phpstan-symfony/issues/255 for the context.
11+
*
12+
* To register it in the configuration file use the `phpstan.resultCacheMetaExtension` service tag:
13+
*
14+
* ```
15+
* services:
16+
* -
17+
* class: App\PHPStan\MyExtension
18+
* tags:
19+
* - phpstan.resultCacheMetaExtension
20+
* ```
21+
*
22+
* @api
23+
*/
24+
interface ResultCacheMetaExtension
25+
{
26+
27+
public const EXTENSION_TAG = 'phpstan.resultCacheMetaExtension';
28+
29+
/**
30+
* Returns unique key for this result cache meta entry. This describes the source of the metadata.
31+
*/
32+
public function getKey(): string;
33+
34+
/**
35+
* Returns hash of the result cache meta entry. This represents the current state of the additional meta source.
36+
*/
37+
public function getHash(): string;
38+
39+
}

src/DependencyInjection/ConditionalTagsExtension.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Nette;
66
use Nette\DI\CompilerExtension;
77
use Nette\Schema\Expect;
8+
use PHPStan\Analyser\ResultCache\ResultCacheMetaExtension;
89
use PHPStan\Analyser\TypeSpecifierFactory;
910
use PHPStan\Broker\BrokerFactory;
1011
use PHPStan\Collectors\RegistryFactory as CollectorRegistryFactory;
@@ -59,6 +60,7 @@ public function getConfigSchema(): Nette\Schema\Schema
5960
LazyParameterOutTypeExtensionProvider::METHOD_TAG => $bool,
6061
LazyParameterOutTypeExtensionProvider::STATIC_METHOD_TAG => $bool,
6162
DiagnoseExtension::EXTENSION_TAG => $bool,
63+
ResultCacheMetaExtension::EXTENSION_TAG => $bool,
6264
])->min(1));
6365
}
6466

0 commit comments

Comments
 (0)