1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
/** |
5
|
|
|
* @author SignpostMarv |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace SignpostMarv\DaftInterfaceCollector; |
9
|
|
|
|
10
|
|
|
use Generator; |
11
|
|
|
use InvalidArgumentException; |
12
|
|
|
use ReflectionMethod; |
13
|
|
|
use Traversable; |
14
|
|
|
|
15
|
|
|
class StaticMethodCollector |
16
|
|
|
{ |
17
|
|
|
/** |
18
|
|
|
* @param array<string, array<int, string>> $staticMethods |
19
|
|
|
*/ |
20
|
|
|
private $staticMethods; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @var array<int, string> |
24
|
|
|
*/ |
25
|
|
|
private $processedSources = []; |
26
|
|
|
|
27
|
2 |
|
public function __construct(array $staticMethods) |
28
|
|
|
{ |
29
|
2 |
|
$filtered = array_map( |
30
|
|
|
/** |
31
|
|
|
* @return string[] |
32
|
|
|
*/ |
33
|
|
|
function (array $shouldContainInterfaces) : array { |
34
|
|
|
/** |
35
|
|
|
* @var string[] $out |
36
|
|
|
*/ |
37
|
2 |
|
$out = array_filter($shouldContainInterfaces, [$this, 'shouldContainInterfaces']); |
38
|
|
|
|
39
|
2 |
|
return array_values($out); |
40
|
2 |
|
}, |
41
|
2 |
|
array_filter($staticMethods, 'is_array') |
42
|
|
|
); |
43
|
|
|
|
44
|
2 |
|
$this->staticMethods = $filtered; |
45
|
2 |
|
} |
46
|
|
|
|
47
|
2 |
|
public function Collect(string ...$implementations) : Generator |
48
|
|
|
{ |
49
|
2 |
|
$this->processedSources = []; |
50
|
|
|
|
51
|
2 |
|
yield from $this->CollectInterfaces(...$implementations); |
52
|
2 |
|
} |
53
|
|
|
|
54
|
2 |
|
protected function CollectInterfaces(string ...$implementations) : Generator |
55
|
|
|
{ |
56
|
2 |
|
foreach (array_filter($implementations, 'class_exists') as $implementation) { |
57
|
2 |
|
$this->processedSources[] = $implementation; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @var string $method |
61
|
|
|
* @var array<int, string> $interfaces |
62
|
|
|
*/ |
63
|
2 |
|
foreach ($this->staticMethods as $method => $interfaces) { |
64
|
2 |
|
if ( ! method_exists($implementation, $method)) { |
65
|
2 |
|
continue; |
66
|
|
|
} |
67
|
|
|
|
68
|
2 |
|
$ref = new ReflectionMethod($implementation, $method); |
69
|
|
|
|
70
|
|
|
if ( |
71
|
2 |
|
! $ref->isStatic() || |
72
|
2 |
|
! $ref->isPublic() || |
73
|
2 |
|
0 < $ref->getNumberOfRequiredParameters() || |
74
|
2 |
|
! $ref->hasReturnType() |
75
|
|
|
) { |
76
|
|
|
continue; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* @var \ReflectionType $refReturn |
81
|
|
|
*/ |
82
|
2 |
|
$refReturn = $ref->getReturnType(); |
83
|
|
|
|
84
|
|
|
if ( |
85
|
|
|
! ( |
86
|
2 |
|
'array' === $refReturn->__toString() || |
|
|
|
|
87
|
2 |
|
is_a((string) $refReturn->__toString(), Traversable::class, true) |
|
|
|
|
88
|
|
|
) |
89
|
|
|
) { |
90
|
|
|
continue; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @var array|Traversable $methodResult |
95
|
|
|
*/ |
96
|
2 |
|
$methodResult = $implementation::$method(); |
97
|
|
|
|
98
|
2 |
|
if (is_iterable($methodResult)) { |
99
|
|
|
/** |
100
|
|
|
* @var string $perhapsYield |
101
|
|
|
*/ |
102
|
|
|
foreach ( |
103
|
2 |
|
array_filter( |
104
|
|
|
( |
105
|
2 |
|
is_array($methodResult) |
106
|
2 |
|
? $methodResult |
107
|
2 |
|
: iterator_to_array($methodResult) |
108
|
|
|
), |
109
|
2 |
|
'is_string' |
110
|
|
|
) as $perhapsYield |
111
|
|
|
) { |
112
|
2 |
|
foreach ($interfaces as $interface) { |
113
|
2 |
|
if (is_a($perhapsYield, $interface, true)) { |
114
|
2 |
|
yield $perhapsYield; |
115
|
2 |
|
break; |
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
if ( |
120
|
2 |
|
! in_array($perhapsYield, $this->processedSources, true) |
121
|
|
|
) { |
122
|
2 |
|
yield from $this->CollectInterfaces($perhapsYield); |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
} |
128
|
2 |
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* @param mixed $maybe |
132
|
|
|
*/ |
133
|
2 |
|
protected function shouldContainInterfaces($maybe) : bool |
134
|
|
|
{ |
135
|
2 |
|
return is_string($maybe) && interface_exists($maybe); |
136
|
|
|
} |
137
|
|
|
} |
138
|
|
|
|
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.