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

AbstractClassifier   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 79
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 27
c 2
b 1
f 0
dl 0
loc 79
ccs 27
cts 27
cp 1
rs 10
wmc 12

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getFiles() 0 7 1
A withFilter() 0 6 1
A find() 0 7 3
A skipDeclaration() 0 19 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Classifier;
6
7
use ReflectionClass;
8
use Symfony\Component\Finder\Finder;
9
use Yiisoft\Classifier\Filter\FilterInterface;
10
11
/**
12
 * Base implementation for {@see ClassifierInterface} with common filters.
13
 */
14
abstract class AbstractClassifier implements ClassifierInterface
15
{
16
    /**
17
     * @var array<class-string|trait-string, ReflectionClass>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string|trait-string, ReflectionClass> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string|trait-string, ReflectionClass>.
Loading history...
18
     */
19
    protected static array $reflectionsCache = [];
20
21
    /**
22
     * @var FilterInterface[]
23
     */
24
    private array $filters = [];
25
    /**
26
     * @var string[]
27
     */
28
    protected array $directories;
29
30 34
    public function __construct(string $directory, string ...$directories)
31
    {
32 34
        $this->directories = [$directory, ...array_values($directories)];
0 ignored issues
show
Documentation Bug introduced by
array($directory, array_values($directories)) is of type array<integer,array|string>, but the property $directories was declared to be of type string[]. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
33
    }
34
35 34
    public function withFilter(FilterInterface ...$filter): static
36
    {
37 34
        $new = clone $this;
38 34
        array_push($new->filters, ...array_values($filter));
39
40 34
        return $new;
41
    }
42
43
    /**
44
     * @return iterable<class-string>
45
     */
46 34
    public function find(): iterable
47
    {
48 34
        foreach ($this->getAvailableDeclarations() as $declaration) {
49 34
            if ($this->skipDeclaration($declaration)) {
50 26
                continue;
51
            }
52 26
            yield $declaration;
53
        }
54
    }
55
56 34
    protected function getFiles(): Finder
57
    {
58 34
        return (new Finder())
59 34
            ->in($this->directories)
60 34
            ->name('*.php')
61 34
            ->sortByName()
62 34
            ->files();
63
    }
64
65
    /**
66
     * @param class-string|trait-string $declaration
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string|trait-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string|trait-string.
Loading history...
67
     */
68 34
    private function skipDeclaration(string $declaration): bool
69
    {
70
        try {
71 34
            $reflectionClass = self::$reflectionsCache[$declaration] ??= new ReflectionClass($declaration);
72 13
        } catch (\Throwable) {
73 13
            return true;
74
        }
75
76 34
        if ($reflectionClass->isInternal() || $reflectionClass->isAnonymous()) {
77 13
            return true;
78
        }
79
80 34
        foreach ($this->filters as $filter) {
81 34
            if (!$filter->match($reflectionClass)) {
82 26
                return true;
83
            }
84
        }
85
86 26
        return false;
87
    }
88
89
    /**
90
     * @return iterable<class-string|trait-string>
91
     */
92
    abstract protected function getAvailableDeclarations(): iterable;
93
}
94