1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Eclipxe\Enum\Internal; |
6
|
|
|
|
7
|
|
|
use Eclipxe\Enum\Exceptions\IndexOverrideException; |
8
|
|
|
use Eclipxe\Enum\Exceptions\ValueOverrideException; |
9
|
|
|
use ReflectionClass; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* This is a helper that perform discovery |
13
|
|
|
* |
14
|
|
|
* This is an internal class, do not use it by your own. Changes on this class are not library breaking changes. |
15
|
|
|
* @internal |
16
|
|
|
*/ |
17
|
|
|
class EntriesPopulator |
18
|
|
|
{ |
19
|
|
|
/** @var string */ |
20
|
|
|
private $className; |
21
|
|
|
|
22
|
|
|
/** @var array */ |
23
|
|
|
private $overrideValues; |
24
|
|
|
|
25
|
|
|
/** @var array */ |
26
|
|
|
private $overrideIndices; |
27
|
|
|
|
28
|
|
|
/** @var Entries */ |
29
|
|
|
private $parentEntries; |
30
|
|
|
|
31
|
60 |
|
public function __construct( |
32
|
|
|
string $className, |
33
|
|
|
array $overrideValues, |
34
|
|
|
array $overrideIndices, |
35
|
|
|
Entries $parentEntries |
36
|
|
|
) { |
37
|
60 |
|
$this->className = $className; |
38
|
60 |
|
$this->overrideValues = $overrideValues; |
39
|
60 |
|
$this->overrideIndices = $overrideIndices; |
40
|
60 |
|
$this->parentEntries = $parentEntries; |
41
|
60 |
|
} |
42
|
|
|
|
43
|
6 |
|
public function getClassName(): string |
44
|
|
|
{ |
45
|
6 |
|
return $this->className; |
46
|
|
|
} |
47
|
|
|
|
48
|
6 |
|
public function populate(Entries $entries): void |
49
|
|
|
{ |
50
|
|
|
// populate with parents first |
51
|
6 |
|
$entries->append($this->parentEntries); |
52
|
|
|
|
53
|
|
|
// populate with discovered |
54
|
6 |
|
$names = array_filter( |
55
|
6 |
|
$this->resolveNamesFromDocBlocks(), |
56
|
|
|
function (string $name) use ($entries) { |
57
|
5 |
|
return ! $entries->hasName($name); |
58
|
6 |
|
} |
59
|
|
|
); |
60
|
6 |
|
foreach ($names as $name) { |
61
|
5 |
|
$newValue = $this->overrideValue($name) ?? $name; |
62
|
5 |
|
if (null !== $entries->findEntryByValue($newValue)) { |
|
|
|
|
63
|
1 |
|
throw ValueOverrideException::create($this->getClassName(), $newValue); |
64
|
|
|
} |
65
|
|
|
|
66
|
5 |
|
$newIndex = $this->overrideIndex($name) ?? $entries->nextIndex(); |
67
|
5 |
|
if (null !== $entries->findEntryByIndex($newIndex)) { |
|
|
|
|
68
|
1 |
|
throw IndexOverrideException::create($this->getClassName(), strval($newIndex)); |
69
|
|
|
} |
70
|
|
|
|
71
|
5 |
|
$entries->put($name, new Entry($newValue, $newIndex)); |
72
|
|
|
} |
73
|
4 |
|
} |
74
|
|
|
|
75
|
5 |
|
public function overrideValue(string $name): ?string |
76
|
|
|
{ |
77
|
5 |
|
$value = $this->overrideValues[$name] ?? null; |
78
|
5 |
|
if (null === $value || ! is_string($value)) { |
79
|
4 |
|
return null; |
80
|
|
|
} |
81
|
2 |
|
return $value; |
82
|
|
|
} |
83
|
|
|
|
84
|
5 |
|
public function overrideIndex(string $name): ?int |
85
|
|
|
{ |
86
|
5 |
|
$index = $this->overrideIndices[$name] ?? null; |
87
|
5 |
|
if (null === $index || ! is_int($index)) { |
88
|
5 |
|
return null; |
89
|
|
|
} |
90
|
2 |
|
return $index; |
91
|
|
|
} |
92
|
|
|
|
93
|
6 |
|
public function resolveNamesFromDocBlocks(): array |
94
|
|
|
{ |
95
|
|
|
// get comments |
96
|
6 |
|
$reflectionClass = new ReflectionClass($this->getClassName()); |
97
|
6 |
|
$docComment = strval($reflectionClass->getDocComment()); |
98
|
6 |
|
return $this->resolveNamesFromDocComment($docComment); |
99
|
|
|
} |
100
|
|
|
|
101
|
60 |
|
public function resolveNamesFromDocComment(string $docComment): array |
102
|
|
|
{ |
103
|
|
|
// read declarations @method static self WORD() |
104
|
|
|
// [*\t ]*: any asterisk, space or tab |
105
|
|
|
// [\w]+: any word letters, numbers and underscore |
106
|
|
|
// /m: ^ match beginning of the line |
107
|
60 |
|
preg_match_all('/^[*\t ]*@method static (self|static) ([\w]+)\(\)/m', $docComment, $matches); |
108
|
60 |
|
return $matches[2] ?? []; |
109
|
|
|
} |
110
|
|
|
} |
111
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.