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