Passed
Pull Request — master (#38)
by Rustam
02:20
created

Classifier::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Classifier;
6
7
use ReflectionAttribute;
8
use ReflectionClass;
9
10
final class Classifier extends AbstractClassifier
11
{
12
    /**
13
     * @psalm-var array<class-string, ReflectionClass>
14
     */
15
    private static array $reflectionsCache = [];
16
17
    /**
18
     * @psalm-suppress UnresolvableInclude
19
     */
20 10
    protected function getAvailableClasses(): iterable
21
    {
22 10
        $files = $this->getFiles();
23
24 10
        foreach ($files as $file) {
25 10
            require_once $file;
26
        }
27
28 10
        foreach (get_declared_classes() as $className) {
29 10
            if ($this->skipClass($className)) {
30 10
                continue;
31
            }
32
33 10
            yield $className;
34
        }
35
    }
36
37
    /**
38
     * @psalm-param class-string $className
39
     */
40 10
    private function skipClass(string $className): bool
41
    {
42 10
        $reflectionClass = self::$reflectionsCache[$className] ??= new ReflectionClass($className);
43
44 10
        if ($reflectionClass->isInternal() || $reflectionClass->isAnonymous()) {
45 10
            return true;
46
        }
47 10
        $directories = $this->directories;
48 10
        $isWindows = DIRECTORY_SEPARATOR === '\\';
49
50 10
        if ($isWindows) {
51
            /**
52
             * @psalm-var string[] $directories
53
             */
54
            // @codeCoverageIgnoreStart
55
            $directories = str_replace('/', '\\', $directories);
56
            // @codeCoverageIgnoreEnd
57
        }
58
59 10
        $matchedDirs = array_filter(
60 10
            $directories,
61 10
            static fn($directory) => str_starts_with($reflectionClass->getFileName(), $directory)
62 10
        );
63
64 10
        if (count($matchedDirs) === 0) {
65 10
            return true;
66
        }
67
68 10
        if (!empty($this->interfaces)) {
69 8
            $interfaces = $reflectionClass->getInterfaces();
70 8
            $interfaces = array_map(static fn(ReflectionClass $class) => $class->getName(), $interfaces);
71
72 8
            if (count(array_intersect($this->interfaces, $interfaces)) !== count($this->interfaces)) {
73 5
                return true;
74
            }
75
        }
76
77 10
        if (!empty($this->attributes)) {
78 2
            $attributes = $reflectionClass->getAttributes();
79 2
            $attributes = array_map(
80 2
                static fn(ReflectionAttribute $attribute) => $attribute->getName(),
81 2
                $attributes
82 2
            );
83
84 2
            if (count(array_intersect($this->attributes, $attributes)) !== count($this->attributes)) {
85 2
                return true;
86
            }
87
        }
88
89 10
        return ($this->parentClass !== null) && !is_subclass_of($reflectionClass->getName(), $this->parentClass);
90
    }
91
}
92