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 ( ad494e...01df2f )
by SignpostMarv
02:53
created

StaticMethodCollector::CollectInterfaces()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6.105

Importance

Changes 0
Metric Value
cc 6
eloc 17
nc 4
nop 1
dl 0
loc 26
ccs 12
cts 14
cp 0.8571
crap 6.105
rs 8.439
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
        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 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