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