1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Spiral Framework. Cycle ProxyFactory |
5
|
|
|
* |
6
|
|
|
* @license MIT |
7
|
|
|
* @author Valentin V (Vvval) |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
declare(strict_types=1); |
11
|
|
|
|
12
|
|
|
namespace Cycle\ORM\Promise; |
13
|
|
|
|
14
|
|
|
use Cycle\ORM\Promise\Exception\ProxyFactoryException; |
15
|
|
|
use PhpParser\Node; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* @param string $object |
19
|
|
|
* @param string $property |
20
|
|
|
* @return Node\Stmt\Expression |
21
|
|
|
*/ |
22
|
|
|
function exprUnsetFunc(string $object, string $property): Node\Stmt\Expression |
23
|
|
|
{ |
24
|
|
|
return new Node\Stmt\Expression(funcCall('unset', [ |
25
|
|
|
new Node\Arg(new Node\Expr\PropertyFetch(new Node\Expr\Variable($object), $property)) |
26
|
|
|
])); |
27
|
|
|
} |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @param string $object |
31
|
|
|
* @param string $property |
32
|
|
|
* @return Node\Stmt\Return_ |
33
|
|
|
*/ |
34
|
|
|
function returnIssetFunc(string $object, string $property): Node\Stmt\Return_ |
35
|
|
|
{ |
36
|
|
|
return new Node\Stmt\Return_(funcCall('isset', [ |
37
|
|
|
new Node\Arg(new Node\Expr\PropertyFetch(new Node\Expr\Variable($object), $property)) |
38
|
|
|
])); |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @param string $name |
43
|
|
|
* @param string $object |
44
|
|
|
* @param string $haystackConst |
45
|
|
|
* @return Node\Stmt\If_ |
46
|
|
|
*/ |
47
|
|
|
function ifInConstArray(string $name, string $object, string $haystackConst): Node\Stmt\If_ |
48
|
|
|
{ |
49
|
|
|
return new Node\Stmt\If_(funcCall('in_array', [ |
50
|
|
|
new Node\Arg(new Node\Expr\Variable($name)), |
51
|
|
|
new Node\Arg(new Node\Expr\ClassConstFetch(new Node\Name($object), $haystackConst)), |
52
|
|
|
new Node\Arg(constFetch('true')) |
53
|
|
|
])); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @param Node\Expr $condition |
58
|
|
|
* @param Node\Stmt $stmt |
59
|
|
|
* @param string $message |
60
|
|
|
* @param array $args |
61
|
|
|
* @return Node\Stmt\If_ |
62
|
|
|
*/ |
63
|
|
|
function throwExceptionOnNull( |
64
|
|
|
Node\Expr $condition, |
65
|
|
|
Node\Stmt $stmt, |
66
|
|
|
string $message = 'Promise not loaded', |
67
|
|
|
array $args = [] |
68
|
|
|
): Node\Stmt\If_ { |
69
|
|
|
$if = ifNotNull($condition); |
70
|
|
|
$if->stmts[] = $stmt; |
71
|
|
|
$if->else = new Node\Stmt\Else_(); |
72
|
|
|
$if->else->stmts[] = throwException(shortName(ProxyFactoryException::class), $message, $args); |
|
|
|
|
73
|
|
|
|
74
|
|
|
return $if; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* @param Node\Expr $expr |
79
|
|
|
* @param array $subNodes |
80
|
|
|
* @return Node\Stmt\If_ |
81
|
|
|
*/ |
82
|
|
|
function ifNotNull(Node\Expr $expr, array $subNodes = []): Node\Stmt\If_ |
83
|
|
|
{ |
84
|
|
|
return new Node\Stmt\If_(new Node\Expr\BinaryOp\NotIdentical($expr, constFetch('null')), $subNodes); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* @param string $var |
89
|
|
|
* @param string $object |
90
|
|
|
* @param string $property |
91
|
|
|
* @param string $method |
92
|
|
|
* @return Node\Stmt\Expression |
93
|
|
|
*/ |
94
|
|
|
function resolveIntoVar( |
95
|
|
|
string $var, |
96
|
|
|
string $object, |
97
|
|
|
string $property, |
98
|
|
|
string $method |
99
|
|
|
): Node\Stmt\Expression { |
100
|
|
|
return new Node\Stmt\Expression( |
101
|
|
|
new Node\Expr\Assign( |
102
|
|
|
new Node\Expr\Variable($var), |
103
|
|
|
resolveMethodCall($object, $property, $method) |
104
|
|
|
) |
105
|
|
|
); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* @param string $object |
110
|
|
|
* @param string $property |
111
|
|
|
* @param string $method |
112
|
|
|
* @return Node\Expr\MethodCall |
113
|
|
|
*/ |
114
|
|
|
function resolveMethodCall(string $object, string $property, string $method): Node\Expr\MethodCall |
115
|
|
|
{ |
116
|
|
|
return new Node\Expr\MethodCall(resolvePropertyFetch($object, $property), $method); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* @param Node\Expr $expr |
121
|
|
|
* @return Node\Stmt\If_ |
122
|
|
|
*/ |
123
|
|
|
function ifEqualsFalse(Node\Expr $expr): Node\Stmt\If_ |
124
|
|
|
{ |
125
|
|
|
return new Node\Stmt\If_(new Node\Expr\BinaryOp\Identical($expr, constFetch('false'))); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* @param string $name |
130
|
|
|
* @return Node\Expr\ConstFetch |
131
|
|
|
*/ |
132
|
|
|
function constFetch(string $name): Node\Expr\ConstFetch |
133
|
|
|
{ |
134
|
|
|
return new Node\Expr\ConstFetch(new Node\Name($name)); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* @param string $property |
139
|
|
|
* @return Node\Stmt\Expression |
140
|
|
|
*/ |
141
|
|
|
function exprClone(string $property): Node\Stmt\Expression |
142
|
|
|
{ |
143
|
|
|
$fetchedProperty = resolvePropertyFetch('this', $property); |
144
|
|
|
|
145
|
|
|
return new Node\Stmt\Expression( |
146
|
|
|
new Node\Expr\Assign($fetchedProperty, new Node\Expr\Clone_($fetchedProperty)) |
147
|
|
|
); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @param string $object |
152
|
|
|
* @param string $property |
153
|
|
|
* @return Node\Expr\PropertyFetch |
154
|
|
|
*/ |
155
|
|
|
function resolvePropertyFetch(string $object, string $property): Node\Expr\PropertyFetch |
156
|
|
|
{ |
157
|
|
|
return new Node\Expr\PropertyFetch(new Node\Expr\Variable($object), $property); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* @param string $name |
162
|
|
|
* @param array $args |
163
|
|
|
* @param array $attributes |
164
|
|
|
* @return Node\Expr\FuncCall |
165
|
|
|
* @internal |
166
|
|
|
*/ |
167
|
|
|
function funcCall(string $name, array $args = [], array $attributes = []): Node\Expr\FuncCall |
168
|
|
|
{ |
169
|
|
|
return new Node\Expr\FuncCall(new Node\Name($name), $args, $attributes); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* @param string $class |
174
|
|
|
* @param string $message |
175
|
|
|
* @param array $args |
176
|
|
|
* @return Node\Stmt\Throw_ |
177
|
|
|
* @internal |
178
|
|
|
*/ |
179
|
|
|
function throwException(string $class, string $message, array $args = []): Node\Stmt\Throw_ |
180
|
|
|
{ |
181
|
|
|
$normalizedArgs = []; |
182
|
|
|
foreach ($args as $arg) { |
183
|
|
|
if (is_scalar($arg)) { |
184
|
|
|
$normalizedArgs[] = new Node\Arg(new Node\Scalar\String_($arg)); |
185
|
|
|
} elseif ($arg instanceof Node\Arg) { |
186
|
|
|
$normalizedArgs[] = $arg; |
187
|
|
|
} |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
return new Node\Stmt\Throw_( |
191
|
|
|
new Node\Expr\New_(new Node\Name($class), [ |
192
|
|
|
new Node\Arg(funcCall( |
193
|
|
|
'sprintf', |
194
|
|
|
array_merge( |
195
|
|
|
[new Node\Arg(new Node\Scalar\String_($message))], |
196
|
|
|
$normalizedArgs |
197
|
|
|
) |
198
|
|
|
)) |
199
|
|
|
]) |
200
|
|
|
); |
201
|
|
|
} |
202
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.