1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
/** |
5
|
|
|
* @author SignpostMarv |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace SignpostMarv\DaftInterfaceCollector; |
9
|
|
|
|
10
|
|
|
use Generator; |
11
|
|
|
use ReflectionClass; |
12
|
|
|
use ReflectionMethod; |
13
|
|
|
use Traversable; |
14
|
|
|
|
15
|
|
|
class StaticMethodCollector |
16
|
|
|
{ |
17
|
|
|
/** |
18
|
|
|
* @var array<string, array<int, string>> |
19
|
|
|
*/ |
20
|
|
|
private $staticMethods; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @var string[] |
24
|
|
|
*/ |
25
|
|
|
private $interfaces = []; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var array<int, string> |
29
|
|
|
*/ |
30
|
|
|
private $processedSources = []; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var string[] |
34
|
|
|
*/ |
35
|
|
|
private $alreadyYielded = []; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var bool |
39
|
|
|
*/ |
40
|
|
|
private $autoResetProcessedSources; |
41
|
|
|
|
42
|
4 |
|
public function __construct( |
43
|
|
|
array $staticMethods, |
44
|
|
|
array $interfaces, |
45
|
|
|
bool $autoResetProcessedSources = true |
46
|
|
|
) { |
47
|
4 |
|
$staticMethods = array_filter( |
48
|
4 |
|
$staticMethods, |
49
|
|
|
/** |
50
|
|
|
* @param mixed $maybe |
51
|
|
|
*/ |
52
|
|
|
function ($maybe) : bool { |
53
|
4 |
|
return is_string($maybe) && interface_exists($maybe); |
54
|
4 |
|
}, |
55
|
4 |
|
ARRAY_FILTER_USE_KEY |
56
|
|
|
); |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var array<string, array<int, string>> $filtered |
60
|
|
|
*/ |
61
|
4 |
|
$filtered = []; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @var string $interface |
65
|
|
|
* @var array<string, array<int, string>> $methods |
66
|
|
|
*/ |
67
|
4 |
|
foreach ($staticMethods as $interface => $methods) { |
68
|
4 |
|
$ref = new ReflectionClass($interface); |
69
|
|
|
|
70
|
4 |
|
$filtered[$interface] = array_filter( |
71
|
4 |
|
$methods, |
72
|
|
|
/** |
73
|
|
|
* @param mixed $maybe |
74
|
|
|
*/ |
75
|
|
|
function ($maybe) use ($ref) : bool { |
76
|
4 |
|
if (is_string($maybe) && $ref->hasMethod($maybe)) { |
77
|
|
|
/** |
78
|
|
|
* @var ReflectionMethod $refMethod |
79
|
|
|
*/ |
80
|
4 |
|
$refMethod = $ref->getMethod($maybe); |
81
|
|
|
|
82
|
|
|
if ( |
83
|
4 |
|
$refMethod->isStatic() && |
84
|
4 |
|
$refMethod->isPublic() && |
85
|
4 |
|
0 === $refMethod->getNumberOfRequiredParameters() && |
86
|
4 |
|
$refMethod->hasReturnType() |
87
|
|
|
) { |
88
|
|
|
/** |
89
|
|
|
* @var \ReflectionType $refReturn |
90
|
|
|
*/ |
91
|
4 |
|
$refReturn = $refMethod->getReturnType(); |
92
|
|
|
|
93
|
|
|
return |
94
|
4 |
|
'array' === $refReturn->__toString() || |
|
|
|
|
95
|
4 |
|
is_a((string) $refReturn->__toString(), Traversable::class, true); |
|
|
|
|
96
|
|
|
} |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
return false; |
100
|
4 |
|
}, |
101
|
4 |
|
ARRAY_FILTER_USE_KEY |
102
|
|
|
); |
103
|
|
|
|
104
|
4 |
|
$filtered[$interface] = array_map( |
105
|
|
|
function (array $methodInterfaces) : array { |
106
|
4 |
|
return array_filter( |
107
|
4 |
|
$methodInterfaces, |
108
|
|
|
/** |
109
|
|
|
* @param mixed $maybe |
110
|
|
|
*/ |
111
|
|
|
function ($maybe) : bool { |
112
|
4 |
|
return is_string($maybe) && interface_exists($maybe); |
113
|
4 |
|
} |
114
|
|
|
); |
115
|
4 |
|
}, |
116
|
4 |
|
$filtered[$interface] |
117
|
|
|
); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* @var array<string, array<int, string>> $filtered |
122
|
|
|
*/ |
123
|
|
|
$filtered = array_filter($filtered, function (array $methods) : bool { |
124
|
4 |
|
return count($methods) > 0; |
125
|
4 |
|
}); |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @var string[] $filteredInterfaces |
129
|
|
|
*/ |
130
|
4 |
|
$filteredInterfaces = array_filter( |
131
|
4 |
|
$interfaces, |
132
|
|
|
/** |
133
|
|
|
* @param mixed $maybe |
134
|
|
|
*/ |
135
|
|
|
function ($maybe) : bool { |
136
|
4 |
|
return is_string($maybe) && interface_exists($maybe); |
137
|
4 |
|
} |
138
|
|
|
); |
139
|
|
|
|
140
|
4 |
|
$this->interfaces = $filteredInterfaces; |
141
|
|
|
|
142
|
4 |
|
$this->staticMethods = $filtered; |
143
|
4 |
|
$this->autoResetProcessedSources = $autoResetProcessedSources; |
144
|
4 |
|
} |
145
|
|
|
|
146
|
4 |
|
public function Collect(string ...$implementations) : Generator |
147
|
|
|
{ |
148
|
4 |
|
if ($this->autoResetProcessedSources) { |
149
|
2 |
|
$this->processedSources = []; |
150
|
2 |
|
$this->alreadyYielded = []; |
151
|
|
|
} |
152
|
|
|
|
153
|
4 |
|
if ($this->autoResetProcessedSources) { |
154
|
2 |
|
$this->processedSources = []; |
155
|
2 |
|
$this->alreadyYielded = []; |
156
|
|
|
} |
157
|
|
|
|
158
|
4 |
|
yield from $this->CollectInterfaces(...$implementations); |
159
|
4 |
|
} |
160
|
|
|
|
161
|
4 |
|
protected function CollectInterfaces(string ...$implementations) : Generator |
162
|
|
|
{ |
163
|
|
|
/** |
164
|
|
|
* @var string[] $interfaces |
165
|
|
|
*/ |
166
|
4 |
|
$interfaces = array_keys($this->staticMethods); |
167
|
4 |
|
foreach (array_filter($implementations, 'class_exists') as $implementation) { |
168
|
|
|
if ( |
169
|
4 |
|
in_array($implementation, $this->processedSources, true) || |
170
|
4 |
|
in_array($implementation, $this->alreadyYielded, true) |
171
|
|
|
) { |
172
|
2 |
|
continue; |
173
|
|
|
} |
174
|
4 |
|
$this->processedSources[] = $implementation; |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* @var string $interface |
178
|
|
|
*/ |
179
|
4 |
|
foreach ($this->interfaces as $interface) { |
180
|
4 |
|
if (is_a($implementation, $interface, true)) { |
181
|
|
|
yield $implementation; |
182
|
|
|
$this->alreadyYielded[] = $implementation; |
183
|
4 |
|
break; |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
|
187
|
4 |
|
foreach ($interfaces as $interface) { |
188
|
4 |
|
if (is_a($implementation, $interface, true)) { |
189
|
|
|
/** |
190
|
|
|
* @var string[] $types |
191
|
|
|
*/ |
192
|
4 |
|
foreach ($this->staticMethods[$interface] as $method => $types) { |
193
|
|
|
/** |
194
|
|
|
* @var iterable<string> $methodResult |
195
|
|
|
*/ |
196
|
4 |
|
$methodResult = $implementation::$method(); |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* @var string $result |
200
|
|
|
*/ |
201
|
4 |
|
foreach ($methodResult as $result) { |
202
|
4 |
|
if (in_array($result, $this->alreadyYielded, true)) { |
203
|
|
|
continue; |
204
|
|
|
} |
205
|
4 |
|
foreach ($types as $type) { |
|
|
|
|
206
|
4 |
|
if (is_a($result, $type, true)) { |
207
|
4 |
|
yield $result; |
208
|
4 |
|
$this->alreadyYielded[] = $result; |
209
|
4 |
|
continue; |
210
|
|
|
} |
211
|
|
|
} |
212
|
4 |
|
foreach ($interfaces as $checkResultWithInterface) { |
213
|
4 |
|
if (is_a($result, $checkResultWithInterface, true)) { |
214
|
4 |
|
yield from $this->CollectInterfaces($result); |
215
|
|
|
} |
216
|
|
|
} |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
} |
221
|
|
|
} |
222
|
4 |
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* @param mixed $maybe |
226
|
|
|
*/ |
227
|
|
|
protected function shouldContainInterfaces($maybe) : bool |
228
|
|
|
{ |
229
|
|
|
return is_string($maybe) && interface_exists($maybe); |
230
|
|
|
} |
231
|
|
|
} |
232
|
|
|
|
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.