GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 5a57c9...67f9b9 )
by SignpostMarv
02:47
created

StaticMethodCollector::CollectInterfaces()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 6.1666

Importance

Changes 0
Metric Value
cc 6
eloc 12
nc 5
nop 1
dl 0
loc 20
ccs 10
cts 12
cp 0.8333
crap 6.1666
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
/**
5
* @author SignpostMarv
6
*/
7
8
namespace SignpostMarv\DaftInterfaceCollector;
9
10
use Closure;
11
use Generator;
12
use ReflectionClass;
13
use ReflectionMethod;
14
use ReflectionType;
15
use Traversable;
16
17
class StaticMethodCollector
18
{
19
    /**
20
    * @var array<string, array<string, string[]>>
21
    */
22
    private $staticMethods = [];
23
24
    /**
25
    * @var string[]
26
    */
27
    private $interfaces = [];
28
29
    /**
30
    * @var array<int, string>
31
    */
32
    private $processedSources = [];
33
34
    /**
35
    * @var string[]
36
    */
37
    private $alreadyYielded = [];
38
39
    /**
40
    * @var bool
41
    */
42
    private $autoReset;
43
44 4
    public function __construct(array $staticMethods, array $interfaces, bool $autoReset = true)
45
    {
46 4
        $filteredMethods = [];
47
48 4
        foreach ($this->FilterArrayOfInterfaceOffsets($staticMethods) as $interface => $methods) {
49 4
            $filteredMethods[$interface] = $this->FilterMethods($interface, $methods);
50
        }
51
52
        /**
53
        * @var array<string, array<string, string[]>> $filteredMethods
54
        */
55 4
        $filteredMethods = $this->FilterNonZeroArray($filteredMethods);
56
57 4
        $this->staticMethods = $filteredMethods;
58
59
        /**
60
        * @var string[] $filteredInterfaces
61
        */
62 4
        $filteredInterfaces = $this->FilterArrayOfInterfaces($interfaces);
63
64 4
        $this->interfaces = $filteredInterfaces;
65
66 4
        $this->autoReset = $autoReset;
67 4
    }
68
69 4
    public function Collect(string ...$implementations) : Generator
70
    {
71 4
        if ($this->autoReset) {
72 2
            $this->processedSources = [];
73 2
            $this->alreadyYielded = [];
74
        }
75
76 4
        yield from $this->CollectInterfaces(...$implementations);
77 4
    }
78
79 4
    protected function CollectInterfaces(string ...$implementations) : Generator
80
    {
81 4
        foreach (array_filter($implementations, 'class_exists') as $implementation) {
82
            if (
83 4
                in_array($implementation, $this->processedSources, true) ||
84 4
                in_array($implementation, $this->alreadyYielded, true)
85
            ) {
86 2
                continue;
87
            }
88 4
            $this->processedSources[] = $implementation;
89
90 4
            foreach ($this->interfaces as $interface) {
91 4
                if (is_a($implementation, $interface, true)) {
92
                    yield $implementation;
93
                    $this->alreadyYielded[] = $implementation;
94 4
                    break;
95
                }
96
            }
97
98 4
            yield from $this->CollectInterfacesFromImplementation($implementation);
99
        }
100 4
    }
101
102 4
    private function CollectInterfacesFromImplementation(string $implementation) : Generator
103
    {
104 4
        $interfaces = array_keys($this->staticMethods);
105
        /**
106
        * @var string $interface
107
        */
108 4
        foreach ($this->FilterIsA($implementation, $interfaces) as $interface) {
109 4
            foreach ($this->staticMethods[$interface] as $method => $types) {
110
                /**
111
                * @var iterable<string> $methodResult
112
                */
113 4
                $methodResult = $implementation::$method();
114
115 4
                foreach ($methodResult as $result) {
116 4
                    if (in_array($result, $this->alreadyYielded, true)) {
117
                        continue;
118
                    }
119
                    /**
120
                    * @var string $type
121
                    */
122 4
                    foreach ($this->FilterIsA($result, $types) as $type) {
123 4
                        yield $result;
124 4
                        $this->alreadyYielded[] = $result;
125
                    }
126
                    /**
127
                    * @var string $checkResultWithInterface
128
                    */
129
                    foreach (
130 4
                        $this->FilterIsA($result, $interfaces) as $checkResultWithInterface
131
                    ) {
132 4
                        yield from $this->CollectInterfaces($result);
133
                    }
134
                }
135
            }
136
        }
137 4
    }
138
139 4
    private function FilterIsA(string $implementation, array $interfaces) : array
140
    {
141
        return array_filter($interfaces, function (string $interface) use ($implementation) : bool {
142 4
            return is_a($implementation, $interface, true);
143 4
        });
144
    }
145
146
    /**
147
    * @return string[]|array<string, mixed>
148
    */
149 4
    private function FilterArrayOfInterfaces(array $interfaces, int $flag = 0) : array
150
    {
151 4
        $strings = array_filter($interfaces, 'is_string', $flag);
152
153 4
        return array_filter($strings, 'interface_exists', $flag);
154
    }
155
156
    /**
157
    * @return array<string, array>
158
    */
159 4
    private function FilterArrayOfInterfaceOffsets(array $interfaces) : array
160
    {
161
        /**
162
        * @var array<string, array> $strings
163
        */
164 4
        $strings = $this->FilterArrayOfInterfaces($interfaces, ARRAY_FILTER_USE_KEY);
165
166 4
        return array_filter($strings, 'is_array');
167
    }
168
169 4
    private function MakeMethodFilter(string $interface) : Closure
170
    {
171
        return function (string $maybe) use ($interface) : bool {
172 4
            $ref = new ReflectionClass($interface);
173
174
            return
175 4
                $ref->hasMethod($maybe) &&
176 4
                $this->FilterReflectionMethod($ref->getMethod($maybe));
177 4
        };
178
    }
179
180 4
    private function FilterReflectionMethod(ReflectionMethod $refMethod) : bool
181
    {
182
        return
183 4
            $refMethod->isStatic() &&
184 4
            $refMethod->isPublic() &&
185 4
            0 === $refMethod->getNumberOfRequiredParameters() &&
186 4
            $this->FilterReflectionReturnType($refMethod->getReturnType());
187
    }
188
189 4
    private function FilterReflectionReturnType(? ReflectionType $refReturn) : bool
190
    {
191 4
        $refReturnName = is_null($refReturn) ? '' : $refReturn->__toString();
0 ignored issues
show
Deprecated Code introduced by
The function ReflectionType::__toString() has been deprecated: 7.1.0:8.0.0 Please use getName() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

191
        $refReturnName = is_null($refReturn) ? '' : /** @scrutinizer ignore-deprecated */ $refReturn->__toString();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
192
193 4
        return 'array' === $refReturnName || is_a($refReturnName, Traversable::class, true);
194
    }
195
196
    /**
197
    * @return array<string, string[]>
198
    */
199 4
    private function FilterMethods(string $interface, array $methods) : array
200
    {
201
        /**
202
        * @var array<string, string[]>
203
        */
204 4
        $filteredMethods = $this->FilterNonZeroArray(array_map(
205 4
            [$this, 'FilterArrayOfInterfaces'],
206 4
            array_filter(
207 4
                array_filter($methods, 'is_string', ARRAY_FILTER_USE_KEY),
208 4
                $this->MakeMethodFilter($interface),
209 4
                ARRAY_FILTER_USE_KEY
210
            )
211
        ));
212
213 4
        return $filteredMethods;
214
    }
215
216
    /**
217
    * @var array[]
218
    */
219 4
    private function FilterNonZeroArray(array $in) : array
220
    {
221 4
        return array_filter(
222 4
            $in,
223
            function (array $val) : bool {
224 4
                return count($val) > 0;
225 4
            }
226
        );
227
    }
228
}
229