1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace PHPStan\BetterReflection\SourceLocator\Type;
6:
7: use PHPStan\BetterReflection\Identifier\Identifier;
8: use PHPStan\BetterReflection\Identifier\IdentifierType;
9: use PHPStan\BetterReflection\Reflection\Reflection;
10: use PHPStan\BetterReflection\Reflector\Reflector;
11:
12: use function array_key_exists;
13: use function spl_object_hash;
14: use function sprintf;
15:
16: final class MemoizingSourceLocator implements SourceLocator
17: {
18: /** @var array<string, Reflection|null> indexed by reflector key and identifier cache key */
19: private $cacheByIdentifierKeyAndOid = [];
20:
21: /** @var array<string, list<Reflection>> indexed by reflector key and identifier type cache key */
22: private $cacheByIdentifierTypeKeyAndOid = [];
23: /**
24: * @var \PHPStan\BetterReflection\SourceLocator\Type\SourceLocator
25: */
26: private $wrappedSourceLocator;
27:
28: public function __construct(SourceLocator $wrappedSourceLocator)
29: {
30: $this->wrappedSourceLocator = $wrappedSourceLocator;
31: }
32:
33: public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?\PHPStan\BetterReflection\Reflection\Reflection
34: {
35: $cacheKey = sprintf('%s_%s', $this->reflectorCacheKey($reflector), $this->identifierToCacheKey($identifier));
36:
37: if (array_key_exists($cacheKey, $this->cacheByIdentifierKeyAndOid)) {
38: return $this->cacheByIdentifierKeyAndOid[$cacheKey];
39: }
40:
41: return $this->cacheByIdentifierKeyAndOid[$cacheKey]
42: = $this->wrappedSourceLocator->locateIdentifier($reflector, $identifier);
43: }
44:
45: /** @return list<Reflection> */
46: public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array
47: {
48: $cacheKey = sprintf('%s_%s', $this->reflectorCacheKey($reflector), $this->identifierTypeToCacheKey($identifierType));
49:
50: if (array_key_exists($cacheKey, $this->cacheByIdentifierTypeKeyAndOid)) {
51: return $this->cacheByIdentifierTypeKeyAndOid[$cacheKey];
52: }
53:
54: return $this->cacheByIdentifierTypeKeyAndOid[$cacheKey]
55: = $this->wrappedSourceLocator->locateIdentifiersByType($reflector, $identifierType);
56: }
57:
58: private function reflectorCacheKey(Reflector $reflector): string
59: {
60: return sprintf('type:%s#oid:%s', get_class($reflector), spl_object_hash($reflector));
61: }
62:
63: private function identifierToCacheKey(Identifier $identifier): string
64: {
65: return sprintf('%s#name:%s', $this->identifierTypeToCacheKey($identifier->getType()), $identifier->getName());
66: }
67:
68: private function identifierTypeToCacheKey(IdentifierType $identifierType): string
69: {
70: return sprintf('type:%s', $identifierType->getName());
71: }
72: }
73: