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