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 ( 01df2f...5b838c )
by SignpostMarv
03:00
created

StaticMethodCollector   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 223
Duplicated Lines 0 %

Test Coverage

Coverage 96.34%

Importance

Changes 0
Metric Value
dl 0
loc 223
ccs 79
cts 82
cp 0.9634
rs 9.6
c 0
b 0
f 0
wmc 32

13 Methods

Rating   Name   Duplication   Size   Complexity  
A Collect() 0 8 2
A __construct() 0 23 2
A FilterArrayOfInterfaces() 0 5 1
A FilterIsA() 0 4 1
B CollectInterfacesFromImplementation() 0 26 6
B CollectInterfaces() 0 26 6
A FilterNonZeroArray() 0 6 1
A FilterArrayOfInterfaceOffsets() 0 8 1
A FilterMethods() 0 15 1
A MakeMethodFilter() 0 8 2
A FilterReflectionMethod() 0 7 4
A FilterReflectionReturnType() 0 5 3
A FilterArrayOfInterfacesOrClasses() 0 9 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
    /**
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->FilterArrayOfInterfacesOrClasses($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
        foreach (
82 4
            array_filter(
83 4
                $implementations,
84
                function (string $implementation) : bool {
85
                    return
86 4
                        class_exists($implementation) &&
87 4
                        ! in_array($implementation, $this->processedSources, true);
88 4
                }
89
            ) as $implementation
90
        ) {
91 4
            $this->processedSources[] = $implementation;
92
93 4
            foreach ($this->interfaces as $interface) {
94
                if (
95 4
                    ! in_array($implementation, $this->alreadyYielded, true) &&
96 4
                    is_a($implementation, $interface, true)
97
                ) {
98
                    yield $implementation;
99
                    $this->alreadyYielded[] = $implementation;
100 4
                    break;
101
                }
102
            }
103
104 4
            yield from $this->CollectInterfacesFromImplementation($implementation);
105
        }
106 4
    }
107
108 4
    private function CollectInterfacesFromImplementation(string $implementation) : Generator
109
    {
110 4
        $interfaces = array_keys($this->staticMethods);
111
        /**
112
        * @var string $interface
113
        */
114 4
        foreach ($this->FilterIsA($implementation, $interfaces) as $interface) {
115 4
            foreach ($this->staticMethods[$interface] as $method => $types) {
116
                /**
117
                * @var iterable<string> $methodResult
118
                */
119 4
                $methodResult = $implementation::$method();
120
121 4
                foreach ($methodResult as $result) {
122 4
                    if (in_array($result, $this->alreadyYielded, true)) {
123
                        continue;
124
                    }
125
                    /**
126
                    * @var string $type
127
                    */
128 4
                    foreach ($this->FilterIsA($result, $types) as $type) {
129 4
                        yield $result;
130 4
                        $this->alreadyYielded[] = $result;
131
                    }
132
133 4
                    yield from $this->CollectInterfaces($result);
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 string[]
158
    */
159 4
    private function FilterArrayOfInterfacesOrClasses(array $interfaces) : array
160
    {
161
        /**
162
        * @var string[] $strings
163
        */
164 4
        $strings = array_filter($interfaces, 'is_string');
165
166
        return array_filter($strings, function (string $maybe) : bool {
167 4
            return interface_exists($maybe) || class_exists($maybe);
168 4
        });
169
    }
170
171
    /**
172
    * @return array<string, array>
173
    */
174 4
    private function FilterArrayOfInterfaceOffsets(array $interfaces) : array
175
    {
176
        /**
177
        * @var array<string, array> $strings
178
        */
179 4
        $strings = $this->FilterArrayOfInterfaces($interfaces, ARRAY_FILTER_USE_KEY);
180
181 4
        return array_filter($strings, 'is_array');
182
    }
183
184 4
    private function MakeMethodFilter(string $interface) : Closure
185
    {
186
        return function (string $maybe) use ($interface) : bool {
187 4
            $ref = new ReflectionClass($interface);
188
189
            return
190 4
                $ref->hasMethod($maybe) &&
191 4
                $this->FilterReflectionMethod($ref->getMethod($maybe));
192 4
        };
193
    }
194
195 4
    private function FilterReflectionMethod(ReflectionMethod $refMethod) : bool
196
    {
197
        return
198 4
            $refMethod->isStatic() &&
199 4
            $refMethod->isPublic() &&
200 4
            0 === $refMethod->getNumberOfRequiredParameters() &&
201 4
            $this->FilterReflectionReturnType($refMethod->getReturnType());
202
    }
203
204 4
    private function FilterReflectionReturnType(? ReflectionType $refReturn) : bool
205
    {
206 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

206
        $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...
207
208 4
        return 'array' === $refReturnName || is_a($refReturnName, Traversable::class, true);
209
    }
210
211
    /**
212
    * @return array<string, string[]>
213
    */
214 4
    private function FilterMethods(string $interface, array $methods) : array
215
    {
216
        /**
217
        * @var array<string, string[]>
218
        */
219 4
        $filteredMethods = $this->FilterNonZeroArray(array_map(
220 4
            [$this, 'FilterArrayOfInterfacesOrClasses'],
221 4
            array_filter(
222 4
                array_filter($methods, 'is_string', ARRAY_FILTER_USE_KEY),
223 4
                $this->MakeMethodFilter($interface),
224 4
                ARRAY_FILTER_USE_KEY
225
            )
226
        ));
227
228 4
        return $filteredMethods;
229
    }
230
231
    /**
232
    * @var array[]
233
    */
234 4
    private function FilterNonZeroArray(array $in) : array
235
    {
236 4
        return array_filter(
237 4
            $in,
238
            function (array $val) : bool {
239 4
                return count($val) > 0;
240 4
            }
241
        );
242
    }
243
}
244