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 — php7.0 ( 7e56d7...071c3d )
by SignpostMarv
05:59
created

StaticMethodCollector   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 276
Duplicated Lines 0 %

Test Coverage

Coverage 98.04%

Importance

Changes 0
Metric Value
eloc 91
dl 0
loc 276
ccs 100
cts 102
cp 0.9804
rs 9.68
c 0
b 0
f 0
wmc 34

17 Methods

Rating   Name   Duplication   Size   Complexity  
A Collect() 0 8 2
A CollectInterfacesFromImplementation() 0 10 3
A FilterNonZeroArray() 0 13 1
A CollectInterfacesFromImplementationCheckInterfaces() 0 16 3
A FilterArrayOfInterfaceOffsets() 0 8 1
A FilterArrayOfInterfaces() 0 7 1
A IsStringInArray() 0 3 1
A FilterMethods() 0 15 1
A CollectInterfaces() 0 14 2
A FilterIsA() 0 10 1
A MakeMethodFilter() 0 8 2
A CollectInterfacesFromImplementationTypes() 0 21 4
A IsStringA() 0 3 1
A FilterReflectionMethod() 0 7 4
A FilterReflectionReturnType() 0 5 3
A FilterArrayOfInterfacesOrClasses() 0 9 2
A __construct() 0 21 2
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
    const DEFAULT_INT_ARRAY_FILTER_FLAG = 0;
20
21
    const DEFAULT_BOOL_AUTORESET = true;
22
23
    const INT_FILTER_NON_EMPTY_ARRAY = 0;
24
25
    const EXPECTED_NUMBER_OF_REQUIRED_PARAMETERS = 0;
26
27
    /**
28
    * @var array<int, string>
29
    */
30
    protected $processedSources = [];
31
32
    /**
33
    * @var string[]
34
    */
35
    protected $alreadyYielded = [];
36
37
    /**
38
    * @var bool
39
    */
40
    protected $autoReset;
41
42
    /**
43
    * @var array<string, array<string, array<int, string>>>
44
    */
45
    private $staticMethods = [];
46
47
    /**
48
    * @var string[]
49
    */
50
    private $interfaces = [];
51
52 4
    public function __construct(
53
        array $staticMethods,
54
        array $interfaces,
55
        bool $autoReset = self::DEFAULT_BOOL_AUTORESET
56
    ) {
57 4
        $filteredMethods = [];
58
59 4
        foreach ($this->FilterArrayOfInterfaceOffsets($staticMethods) as $interface => $methods) {
60 4
            $filteredMethods[$interface] = $this->FilterMethods($interface, $methods);
61
        }
62
63 4
        $this->staticMethods = $this->FilterNonZeroArray($filteredMethods);
64
65
        /**
66
        * @var string[]
67
        */
68 4
        $filteredInterfaces = $this->FilterArrayOfInterfacesOrClasses($interfaces);
69
70 4
        $this->interfaces = $filteredInterfaces;
71
72 4
        $this->autoReset = $autoReset;
73 4
    }
74
75 2
    public function Collect(string ...$implementations) : Generator
76
    {
77 2
        if ($this->autoReset) {
78 1
            $this->processedSources = [];
79 1
            $this->alreadyYielded = [];
80
        }
81
82 2
        yield from $this->CollectInterfaces(...$implementations);
83 2
    }
84
85 4
    protected function CollectInterfaces(string ...$implementations) : Generator
86
    {
87
        foreach (
88 4
            array_filter(
89 4
                $implementations,
90 4
                function (string $implementation) : bool {
91
                    return
92 4
                        ! static::IsStringInArray($implementation, $this->processedSources);
93 4
                }
94
            ) as $implementation
95
        ) {
96 4
            $this->processedSources[] = $implementation;
97 4
            yield from $this->CollectInterfacesFromImplementationCheckInterfaces($implementation);
98 4
            yield from $this->CollectInterfacesFromImplementation($implementation);
99
        }
100 4
    }
101
102 4
    final protected function CollectInterfacesFromImplementationCheckInterfaces(
103
        string $implementation
104
    ) : Generator {
105 4
        $checking = array_filter(
106 4
            $this->interfaces,
107 4
            function (string $interface) use ($implementation) : bool {
108 4
                return static::IsStringA($implementation, $interface);
109 4
            }
110
        );
111
112
        if (
113 4
            count($checking) > self::INT_FILTER_NON_EMPTY_ARRAY &&
114 4
            ! static::IsStringInArray($implementation, $this->alreadyYielded)
115
        ) {
116
            yield $implementation;
117
            $this->alreadyYielded[] = $implementation;
118
        }
119 4
    }
120
121 4
    final protected function CollectInterfacesFromImplementation(string $implementation) : Generator
122
    {
123 4
        $interfaces = array_keys($this->staticMethods);
124
125 4
        foreach ($this->FilterIsA($implementation, $interfaces) as $interface) {
126 4
            foreach ($this->staticMethods[$interface] as $method => $types) {
127 4
                yield from $this->CollectInterfacesFromImplementationTypes(
128 4
                    $implementation,
129 4
                    $method,
130 4
                    $types
131
                );
132
            }
133
        }
134 4
    }
135
136
    /**
137
    * @param array<int, string> $types
138
    */
139 4
    final protected function CollectInterfacesFromImplementationTypes(
140
        string $implementation,
141
        string $method,
142
        array $types
143
    ) : Generator {
144
        /**
145
        * @var iterable<string>
146
        */
147 4
        $methodResult = $implementation::$method();
148
149 4
        foreach ($methodResult as $result) {
150 4
            if (static::IsStringInArray($result, $this->alreadyYielded)) {
151 1
                continue;
152
            }
153
154 4
            foreach ($this->FilterIsA($result, $types) as $type) {
155 4
                yield $result;
156 4
                $this->alreadyYielded[] = $result;
157
            }
158
159 4
            yield from $this->CollectInterfaces($result);
160
        }
161 4
    }
162
163
    /**
164
    * @param array<int, string> $interfaces
165
    *
166
    * @return array<int, string>
167
    */
168
    final protected function FilterIsA(string $implementation, array $interfaces) : array
169
    {
170
        /**
171
        * @var array<int, string>
172
        */
173 4
        $out = array_filter($interfaces, function (string $interface) use ($implementation) : bool {
174 4
            return static::IsStringA($implementation, $interface);
175 4
        });
176
177 4
        return $out;
178
    }
179
180
    /**
181
    * @return string[]|array<string, mixed>
182
    */
183 4
    final protected function FilterArrayOfInterfaces(
184
        array $interfaces,
185
        int $flag = self::DEFAULT_INT_ARRAY_FILTER_FLAG
186
    ) : array {
187 4
        $strings = array_filter($interfaces, 'is_string', $flag);
188
189 4
        return array_filter($strings, 'interface_exists', $flag);
190
    }
191
192
    /**
193
    * @return string[]
194
    */
195 4
    final protected function FilterArrayOfInterfacesOrClasses(array $interfaces) : array
196
    {
197
        /**
198
        * @var string[]
199
        */
200 4
        $strings = array_filter($interfaces, 'is_string');
201
202 4
        return array_filter($strings, function (string $maybe) : bool {
203 4
            return interface_exists($maybe) || class_exists($maybe);
204 4
        });
205
    }
206
207
    /**
208
    * @return array<string, array>
209
    */
210 4
    final protected function FilterArrayOfInterfaceOffsets(array $interfaces) : array
211
    {
212
        /**
213
        * @var array<string, array>
214
        */
215 4
        $strings = $this->FilterArrayOfInterfaces($interfaces, ARRAY_FILTER_USE_KEY);
216
217 4
        return array_filter($strings, 'is_array');
218
    }
219
220
    final protected function MakeMethodFilter(string $interface) : Closure
221
    {
222 4
        return function (string $maybe) use ($interface) : bool {
223 4
            $ref = new ReflectionClass($interface);
224
225
            return
226 4
                $ref->hasMethod($maybe) &&
227 4
                $this->FilterReflectionMethod($ref->getMethod($maybe));
228 4
        };
229
    }
230
231 4
    final protected function FilterReflectionMethod(ReflectionMethod $refMethod) : bool
232
    {
233
        return
234 4
            $refMethod->isStatic() &&
235 4
            $refMethod->isPublic() &&
236 4
            self::EXPECTED_NUMBER_OF_REQUIRED_PARAMETERS === $refMethod->getNumberOfRequiredParameters() &&
237 4
            $this->FilterReflectionReturnType($refMethod->getReturnType());
238
    }
239
240 4
    final protected function FilterReflectionReturnType(ReflectionType $refReturn = null) : bool
241
    {
242 4
        $refReturnName = ($refReturn instanceof ReflectionType) ? $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

242
        $refReturnName = ($refReturn instanceof ReflectionType) ? /** @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...
243
244 4
        return 'array' === $refReturnName || static::IsStringA($refReturnName, Traversable::class);
245
    }
246
247
    /**
248
    * @return array<string, string[]>
249
    */
250 4
    final protected function FilterMethods(string $interface, array $methods) : array
251
    {
252
        /**
253
        * @var array<string, string[]>
254
        */
255 4
        $filteredMethods = $this->FilterNonZeroArray(array_map(
256 4
            [$this, 'FilterArrayOfInterfacesOrClasses'],
257 4
            array_filter(
258 4
                array_filter($methods, 'is_string', ARRAY_FILTER_USE_KEY),
259 4
                $this->MakeMethodFilter($interface),
260 4
                ARRAY_FILTER_USE_KEY
261
            )
262
        ));
263
264 4
        return $filteredMethods;
265
    }
266
267
    /**
268
    * @return array<string, array<string, array<int, string>>>
269
    */
270 4
    final protected function FilterNonZeroArray(array $in) : array
271
    {
272
        /**
273
        * @var array<string, array<string, array<int, string>>>
274
        */
275 4
        $out = array_filter(
276 4
            $in,
277 4
            function (array $val) : bool {
278 4
                return count($val) > self::INT_FILTER_NON_EMPTY_ARRAY;
279 4
            }
280
        );
281
282 4
        return $out;
283
    }
284
285 4
    protected static function IsStringInArray(string $maybe, array $array) : bool
286
    {
287 4
        return in_array($maybe, $array, true);
288
    }
289
290 4
    protected static function IsStringA(string $maybe, string $thing) : bool
291
    {
292 4
        return is_a($maybe, $thing, true);
293
    }
294
}
295