1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace PHPStan\BetterReflection\SourceLocator\Type;
6:
7: use Iterator;
8: use PHPStan\BetterReflection\Identifier\Identifier;
9: use PHPStan\BetterReflection\Identifier\IdentifierType;
10: use PHPStan\BetterReflection\Reflection\Reflection;
11: use PHPStan\BetterReflection\Reflector\Reflector;
12: use PHPStan\BetterReflection\SourceLocator\Ast\Locator;
13: use PHPStan\BetterReflection\SourceLocator\Exception\InvalidFileInfo;
14: use PHPStan\BetterReflection\SourceLocator\Exception\InvalidFileLocation;
15: use SplFileInfo;
16:
17: use function array_filter;
18: use function array_map;
19: use function array_values;
20: use function iterator_to_array;
21:
22: /**
23: * This source locator loads all php files from \FileSystemIterator
24: */
25: class FileIteratorSourceLocator implements SourceLocator
26: {
27: private Locator $astLocator;
28: /**
29: * @var \PHPStan\BetterReflection\SourceLocator\Type\AggregateSourceLocator|null
30: */
31: private $aggregateSourceLocator = null;
32:
33: /** @var Iterator<SplFileInfo> */
34: private Iterator $fileSystemIterator;
35:
36: /**
37: * @param Iterator<SplFileInfo> $fileInfoIterator note: only SplFileInfo allowed in this iterator
38: *
39: * @throws InvalidFileInfo In case of iterator not contains only SplFileInfo.
40: */
41: public function __construct(Iterator $fileInfoIterator, Locator $astLocator)
42: {
43: $this->astLocator = $astLocator;
44: foreach ($fileInfoIterator as $fileInfo) {
45: /** @phpstan-ignore instanceof.alwaysTrue */
46: if (! $fileInfo instanceof SplFileInfo) {
47: throw InvalidFileInfo::fromNonSplFileInfo($fileInfo);
48: }
49: }
50:
51: $this->fileSystemIterator = $fileInfoIterator;
52: }
53:
54: /** @throws InvalidFileLocation */
55: private function getAggregatedSourceLocator(): AggregateSourceLocator
56: {
57: // @infection-ignore-all Coalesce: There's no difference, it's just optimization
58: return $this->aggregateSourceLocator
59: ?? $this->aggregateSourceLocator = new AggregateSourceLocator(array_values(array_filter(array_map(
60: function (SplFileInfo $item): ?\PHPStan\BetterReflection\SourceLocator\Type\SingleFileSourceLocator {
61: if (! ($item->isFile() && $item->getExtension() === 'php')) {
62: return null;
63: }
64:
65: /** @phpstan-var non-empty-string $itemRealPath */
66: $itemRealPath = $item->getRealPath();
67:
68: return new SingleFileSourceLocator($itemRealPath, $this->astLocator);
69: },
70: iterator_to_array($this->fileSystemIterator),
71: ))));
72: }
73:
74: /**
75: * {@inheritDoc}
76: *
77: * @throws InvalidFileLocation
78: */
79: public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?\PHPStan\BetterReflection\Reflection\Reflection
80: {
81: return $this->getAggregatedSourceLocator()->locateIdentifier($reflector, $identifier);
82: }
83:
84: /**
85: * {@inheritDoc}
86: *
87: * @throws InvalidFileLocation
88: */
89: public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array
90: {
91: return $this->getAggregatedSourceLocator()->locateIdentifiersByType($reflector, $identifierType);
92: }
93: }
94: