1
|
|
|
<?php declare(strict_types=1); |
2
|
|
|
|
3
|
|
|
namespace Igni\Utils\ReflectionApi; |
4
|
|
|
|
5
|
|
|
use Igni\Utils\Exception\ReflectionApiException; |
6
|
|
|
use Igni\Utils\ReflectionApi; |
7
|
|
|
|
8
|
|
|
final class RuntimeMethod implements CodeGenerator |
9
|
|
|
{ |
10
|
|
|
use VisibilityTrait; |
11
|
|
|
use AbstractTrait; |
12
|
|
|
use FinalTrait; |
13
|
|
|
use StaticTrait; |
14
|
|
|
|
15
|
|
|
private $returnType = ''; |
16
|
|
|
private $arguments = []; |
17
|
|
|
private $body = []; |
18
|
|
|
private $name; |
19
|
|
|
|
20
|
|
|
private const DEFAULT_TYPES = ['string', 'int', 'object', 'bool', 'float', 'array', 'callable', 'void']; |
21
|
|
|
|
22
|
9 |
|
public function __construct(string $name) |
23
|
|
|
{ |
24
|
9 |
|
$this->name = $name; |
25
|
9 |
|
} |
26
|
|
|
|
27
|
3 |
|
public function getName(): string |
28
|
|
|
{ |
29
|
3 |
|
return $this->name; |
30
|
|
|
} |
31
|
|
|
|
32
|
3 |
|
public function setReturnType(string $type): self |
33
|
|
|
{ |
34
|
3 |
|
if (!in_array($type, self::DEFAULT_TYPES) && !class_exists($type) && !interface_exists($type)) { |
35
|
|
|
throw ReflectionApiException::forUnknownType($type); |
36
|
|
|
} |
37
|
|
|
|
38
|
3 |
|
$this->returnType = $type; |
39
|
|
|
|
40
|
3 |
|
return $this; |
41
|
|
|
} |
42
|
|
|
|
43
|
1 |
|
public function getReturnType(): string |
44
|
|
|
{ |
45
|
1 |
|
return $this->returnType; |
46
|
|
|
} |
47
|
|
|
|
48
|
2 |
|
public function addArgument(RuntimeArgument $argument): self |
49
|
|
|
{ |
50
|
2 |
|
$this->arguments[$argument->getName()] = $argument; |
51
|
|
|
|
52
|
2 |
|
return $this; |
53
|
|
|
} |
54
|
|
|
|
55
|
3 |
|
public function setBody(string ...$lines): self |
56
|
|
|
{ |
57
|
3 |
|
if ($this->abstract) { |
58
|
|
|
throw ReflectionApiException::forAbstractMethodWithBody($this->name); |
59
|
|
|
} |
60
|
|
|
|
61
|
3 |
|
$this->body = $lines; |
62
|
|
|
|
63
|
3 |
|
return $this; |
64
|
|
|
} |
65
|
|
|
|
66
|
1 |
|
public function addLine(string $line): self |
67
|
|
|
{ |
68
|
1 |
|
if ($this->abstract) { |
69
|
|
|
throw ReflectionApiException::forAbstractMethodWithBody($this->name); |
70
|
|
|
} |
71
|
|
|
|
72
|
1 |
|
$this->body[] = $line; |
73
|
|
|
|
74
|
1 |
|
return $this; |
75
|
|
|
} |
76
|
|
|
|
77
|
8 |
|
public function generateCode(): string |
78
|
|
|
{ |
79
|
8 |
|
$code = ''; |
80
|
|
|
|
81
|
8 |
|
if ($this->isAbstract()) { |
82
|
|
|
$code .= 'abstract'; |
83
|
|
|
} |
84
|
|
|
|
85
|
8 |
|
if ($this->isFinal()) { |
86
|
|
|
$code .= 'final '; |
87
|
|
|
} |
88
|
|
|
|
89
|
8 |
|
$code .= $this->getVisibility() . ' '; |
90
|
|
|
|
91
|
8 |
|
if ($this->isStatic()) { |
92
|
|
|
$code .= 'static '; |
93
|
|
|
} |
94
|
8 |
|
$code .= "function {$this->name}("; |
95
|
|
|
|
96
|
8 |
|
if ($this->arguments) { |
|
|
|
|
97
|
2 |
|
$arguments = []; |
98
|
2 |
|
foreach ($this->arguments as $argument) { |
99
|
2 |
|
$arguments[] = $argument->generateCode(); |
100
|
|
|
} |
101
|
|
|
|
102
|
2 |
|
$code .= implode(', ', $arguments); |
103
|
|
|
} |
104
|
|
|
|
105
|
8 |
|
$code .= ')'; |
106
|
8 |
|
if ($this->returnType) { |
107
|
3 |
|
if (class_exists($this->returnType) || interface_exists($this->returnType)) { |
108
|
|
|
$code .= ": \\{$this->returnType}"; |
109
|
|
|
} else { |
110
|
3 |
|
$code .= ": {$this->returnType}"; |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
|
114
|
8 |
|
if ($this->isAbstract()) { |
115
|
|
|
$code .= ';'; |
116
|
|
|
} else { |
117
|
8 |
|
$code .= "\n{"; |
118
|
|
|
|
119
|
8 |
|
if ($this->body) { |
|
|
|
|
120
|
4 |
|
$code .= "\n\t" . implode("\n\t", $this->body); |
121
|
|
|
} |
122
|
|
|
|
123
|
8 |
|
$code .= "\n}"; |
124
|
|
|
} |
125
|
|
|
|
126
|
8 |
|
return $code; |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.