1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* \AppserverIo\Doppelgaenger\Generator |
5
|
|
|
* |
6
|
|
|
* NOTICE OF LICENSE |
7
|
|
|
* |
8
|
|
|
* This source file is subject to the Open Software License (OSL 3.0) |
9
|
|
|
* that is available through the world-wide-web at this URL: |
10
|
|
|
* http://opensource.org/licenses/osl-3.0.php |
11
|
|
|
* |
12
|
|
|
* PHP version 5 |
13
|
|
|
* |
14
|
|
|
* @author Bernhard Wick <[email protected]> |
15
|
|
|
* @copyright 2015 TechDivision GmbH - <[email protected]> |
16
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
17
|
|
|
* @link https://github.com/appserver-io/doppelgaenger |
18
|
|
|
* @link http://www.appserver.io/ |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
namespace AppserverIo\Doppelgaenger; |
22
|
|
|
|
23
|
|
|
use AppserverIo\Doppelgaenger\Entities\Definitions\AbstractStructureDefinition; |
24
|
|
|
use AppserverIo\Doppelgaenger\Entities\Definitions\AspectDefinition; |
25
|
|
|
use AppserverIo\Doppelgaenger\Exceptions\GeneratorException; |
26
|
|
|
use AppserverIo\Doppelgaenger\Entities\Definitions\ClassDefinition; |
27
|
|
|
use AppserverIo\Doppelgaenger\Entities\Definitions\InterfaceDefinition; |
28
|
|
|
use AppserverIo\Doppelgaenger\Entities\Definitions\StructureDefinitionHierarchy; |
29
|
|
|
use AppserverIo\Doppelgaenger\Interfaces\StructureDefinitionInterface; |
30
|
|
|
use AppserverIo\Doppelgaenger\Entities\Definitions\Structure; |
31
|
|
|
use AppserverIo\Doppelgaenger\Parser\StructureParserFactory; |
32
|
|
|
use AppserverIo\Doppelgaenger\Dictionaries\Placeholders; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* This class initiates the creation of enforced structure definitions. |
36
|
|
|
* |
37
|
|
|
* @author Bernhard Wick <[email protected]> |
38
|
|
|
* @copyright 2015 TechDivision GmbH - <[email protected]> |
39
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
40
|
|
|
* @link https://github.com/appserver-io/doppelgaenger |
41
|
|
|
* @link http://www.appserver.io/ |
42
|
|
|
*/ |
43
|
|
|
class Generator |
44
|
|
|
{ |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* The register for any known aspects |
48
|
|
|
* |
49
|
|
|
* @var \AppserverIo\Doppelgaenger\AspectRegister $aspectRegister |
50
|
|
|
*/ |
51
|
|
|
protected $aspectRegister; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* A cacheMap instance to organize our cache |
55
|
|
|
* |
56
|
|
|
* @var \AppserverIo\Doppelgaenger\CacheMap $cacheMap |
57
|
|
|
*/ |
58
|
|
|
protected $cacheMap; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* A structureMap instance to organize the known structures |
62
|
|
|
* |
63
|
|
|
* @var \AppserverIo\Doppelgaenger\StructureMap $structureMap |
64
|
|
|
*/ |
65
|
|
|
protected $structureMap; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* The aspect of the configuration we need |
69
|
|
|
* |
70
|
|
|
* @var \AppserverIo\Doppelgaenger\Config $config |
71
|
|
|
*/ |
72
|
|
|
protected $config; |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Collection of definitions and their inheritance relation to each other |
76
|
|
|
* |
77
|
|
|
* @var \AppserverIo\Doppelgaenger\Entities\Definitions\StructureDefinitionHierarchy $structureDefinitionHierarchy |
78
|
|
|
*/ |
79
|
|
|
protected $structureDefinitionHierarchy; |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Default constructor |
83
|
|
|
* |
84
|
|
|
* @param \AppserverIo\Doppelgaenger\StructureMap $structureMap A structureMap instance to organize the known structures |
85
|
|
|
* @param \AppserverIo\Doppelgaenger\CacheMap $cacheMap A cacheMap instance to organize our cache |
86
|
|
|
* @param \AppserverIo\Doppelgaenger\Config $config Configuration |
87
|
|
|
* @param \AppserverIo\Doppelgaenger\AspectRegister $aspectRegister The register for known aspects |
88
|
|
|
*/ |
89
|
|
|
public function __construct(StructureMap $structureMap, CacheMap $cacheMap, Config $config, AspectRegister $aspectRegister) |
90
|
|
|
{ |
91
|
|
|
$this->cacheMap = $cacheMap; |
92
|
|
|
$this->structureMap = $structureMap; |
93
|
|
|
$this->config = $config; |
94
|
|
|
$this->aspectRegister = $aspectRegister; |
95
|
|
|
$this->structureDefinitionHierarchy = new StructureDefinitionHierarchy(); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Will create an altered definition of the structure defined in the $mapEntry variable. |
100
|
|
|
* Will also add it to the cache map |
101
|
|
|
* |
102
|
|
|
* @param \AppserverIo\Doppelgaenger\Entities\Definitions\Structure $mapEntry Entry of a StructureMap we want created |
103
|
|
|
* @param boolean $createRecursive If contract inheritance is enabled |
104
|
|
|
* |
105
|
|
|
* @throws \AppserverIo\Doppelgaenger\Exceptions\GeneratorException |
106
|
|
|
* |
107
|
|
|
* @return boolean |
108
|
|
|
*/ |
109
|
|
|
public function create(Structure $mapEntry, $createRecursive = false) |
110
|
|
|
{ |
111
|
|
|
// We know what we are searching for and we got a fine factory so lets get us a parser |
112
|
|
|
$structureParserFactory = new StructureParserFactory(); |
113
|
|
|
$parser = $structureParserFactory->getInstance( |
114
|
|
|
$mapEntry->getType(), |
115
|
|
|
$mapEntry->getPath(), |
116
|
|
|
$this->config, |
117
|
|
|
$this->structureMap, |
118
|
|
|
$this->structureDefinitionHierarchy |
119
|
|
|
); |
120
|
|
|
|
121
|
|
|
// Lets get the definition we are looking for |
122
|
|
|
$structureDefinition = $parser->getDefinition($mapEntry->getIdentifier(), $createRecursive); |
123
|
|
|
|
124
|
|
|
if (!$structureDefinition instanceof StructureDefinitionInterface) { |
125
|
|
|
// we did not get what we need, so fail |
126
|
|
|
return false; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
$qualifiedName = $structureDefinition->getQualifiedName(); |
130
|
|
|
$filePath = $this->createFilePath( |
131
|
|
|
$qualifiedName, |
132
|
|
|
$mapEntry->getPath() |
|
|
|
|
133
|
|
|
); |
134
|
|
|
|
135
|
|
|
$tmp = $this->createFileFromDefinition($filePath, $structureDefinition); |
136
|
|
|
|
137
|
|
|
if ($tmp === false) { |
138
|
|
|
// we were not able to create a new definition file, fail |
139
|
|
|
throw new GeneratorException(sprintf('Could not create altered definition for %s', $qualifiedName)); |
140
|
|
|
} |
141
|
|
|
// Now get our new file into the cacheMap |
142
|
|
|
$this->cacheMap->add( |
143
|
|
|
new Structure( |
144
|
|
|
filectime($mapEntry->getPath()), |
145
|
|
|
$qualifiedName, |
146
|
|
|
$filePath, |
147
|
|
|
$structureDefinition->getType() |
148
|
|
|
) |
149
|
|
|
); |
150
|
|
|
|
151
|
|
|
// Still here? Than everything worked out great. |
152
|
|
|
return true; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Will return the path the cached and altered definition will have |
157
|
|
|
* |
158
|
|
|
* @param string $structureName Name of the structure we want to update |
159
|
|
|
* |
160
|
|
|
* @return string |
161
|
|
|
* |
162
|
|
|
* TODO implement this somewhere more accessible, others might need it too (e.g. autoloader) |
|
|
|
|
163
|
|
|
*/ |
164
|
|
|
protected function createFilePath($structureName) |
165
|
|
|
{ |
166
|
|
|
// s a file can contain multiple structures we will substitute the filename with the structure name |
167
|
|
|
$tmpFileName = ltrim(str_replace('\\', '_', $structureName), '_'); |
168
|
|
|
|
169
|
|
|
return $this->config->getValue('cache/dir') . DIRECTORY_SEPARATOR . $tmpFileName . '.php'; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Will create a file containing the altered definition |
174
|
|
|
* |
175
|
|
|
* @param string $targetFileName The intended name of the |
176
|
|
|
* new file |
177
|
|
|
* @param \AppserverIo\Doppelgaenger\Interfaces\StructureDefinitionInterface $structureDefinition The definition of the |
178
|
|
|
* structure we will alter |
179
|
|
|
* |
180
|
|
|
* @throws \InvalidArgumentException |
181
|
|
|
* |
182
|
|
|
* @return boolean |
183
|
|
|
*/ |
184
|
|
|
protected function createFileFromDefinition( |
185
|
|
|
$targetFileName, |
186
|
|
|
StructureDefinitionInterface $structureDefinition |
187
|
|
|
) { |
188
|
|
|
// We have to check which structure type we got |
189
|
|
|
$definitionType = get_class($structureDefinition); |
190
|
|
|
|
191
|
|
|
// Call the method accordingly |
192
|
|
|
$tmp = explode('\\', $definitionType); |
193
|
|
|
$creationMethod = 'createFileFrom' . array_pop($tmp); |
194
|
|
|
|
195
|
|
|
// Check if we got something, if not we will default to class |
196
|
|
|
if (!method_exists($this, $creationMethod)) { |
197
|
|
|
// per default we will try to create a class definition |
198
|
|
|
$creationMethod = 'createFileFromArbitraryDefinition'; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
return $this->$creationMethod($targetFileName, $structureDefinition); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Will create a file with the altered class definition as its content. |
206
|
|
|
* We will register the aspect first |
207
|
|
|
* |
208
|
|
|
* @param string $targetFileName The intended name of the new file |
209
|
|
|
* @param \AppserverIo\Doppelgaenger\Entities\Definitions\AspectDefinition $aspectDefinition The definition of the structure we will alter |
210
|
|
|
* |
211
|
|
|
* @return boolean |
212
|
|
|
*/ |
213
|
|
|
protected function createFileFromAspectDefinition($targetFileName, AspectDefinition $aspectDefinition) |
214
|
|
|
{ |
215
|
|
|
|
216
|
|
|
// register the aspect in our central aspect register |
217
|
|
|
$this->aspectRegister->register($aspectDefinition); |
218
|
|
|
|
219
|
|
|
// create the new definition |
220
|
|
|
return $this->createFileFromArbitraryDefinition($targetFileName, $aspectDefinition); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Will create a file for a given interface definition. |
225
|
|
|
* We will just copy the file here until the autoloader got refactored. |
226
|
|
|
* |
227
|
|
|
* @param string $targetFileName The intended name of the new file |
228
|
|
|
* @param \AppserverIo\Doppelgaenger\Entities\Definitions\InterfaceDefinition $structureDefinition The definition of the structure we will alter |
229
|
|
|
* |
230
|
|
|
* @return boolean |
231
|
|
|
* |
232
|
|
|
* TODO remove when autoloader is able to recognize and skip interfaces |
|
|
|
|
233
|
|
|
*/ |
234
|
|
|
protected function createFileFromInterfaceDefinition( |
235
|
|
|
$targetFileName, |
236
|
|
|
InterfaceDefinition $structureDefinition |
237
|
|
|
) { |
238
|
|
|
// Get the content of the file |
239
|
|
|
$content = file_get_contents($structureDefinition->getPath()); |
240
|
|
|
|
241
|
|
|
// Make the one change we need, the original file path and modification timestamp |
242
|
|
|
$content = str_replace( |
243
|
|
|
'<?php', |
244
|
|
|
'<?php /* ' . Placeholders::ORIGINAL_PATH_HINT . $structureDefinition->getPath() . '#' . |
245
|
|
|
filemtime( |
246
|
|
|
$structureDefinition->getPath() |
247
|
|
|
) . Placeholders::ORIGINAL_PATH_HINT . ' */', |
248
|
|
|
$content |
249
|
|
|
); |
250
|
|
|
|
251
|
|
|
return (boolean)file_put_contents($targetFileName, $content); |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Will create a file with the altered class definition as its content |
256
|
|
|
* |
257
|
|
|
* @param string $targetFileName The intended name of the new file |
258
|
|
|
* @param \AppserverIo\Doppelgaenger\Entities\Definitions\AbstractStructureDefinition $structureDefinition The definition of the structure we will alter |
259
|
|
|
* |
260
|
|
|
* @return boolean |
261
|
|
|
*/ |
262
|
|
|
protected function createFileFromArbitraryDefinition( |
263
|
|
|
$targetFileName, |
|
|
|
|
264
|
|
|
AbstractStructureDefinition $structureDefinition |
265
|
|
|
) { |
266
|
|
|
|
267
|
|
|
$res = fopen( |
268
|
|
|
$this->createFilePath($structureDefinition->getQualifiedName()), |
269
|
|
|
'w+' |
270
|
|
|
); |
271
|
|
|
|
272
|
|
|
// Append all configured filters |
273
|
|
|
$this->appendDefaultFilters($res, $structureDefinition); |
274
|
|
|
|
275
|
|
|
$tmp = fwrite( |
276
|
|
|
$res, |
277
|
|
|
file_get_contents($structureDefinition->getPath(), time()) |
278
|
|
|
); |
279
|
|
|
|
280
|
|
|
// Did we write something? |
281
|
|
|
if ($tmp > 0) { |
282
|
|
|
fclose($res); |
283
|
|
|
|
284
|
|
|
return true; |
285
|
|
|
|
|
|
|
|
286
|
|
|
} else { |
287
|
|
|
// Delete the empty file stub we made |
288
|
|
|
unlink( |
289
|
|
|
$this->createFilePath( |
290
|
|
|
$structureDefinition->getQualifiedName() |
291
|
|
|
), |
292
|
|
|
$res |
293
|
|
|
); |
294
|
|
|
|
295
|
|
|
fclose($res); |
296
|
|
|
|
297
|
|
|
return false; |
298
|
|
|
} |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Will append all needed filters based on the enforcement level stated in the configuration file. |
303
|
|
|
* |
304
|
|
|
* @param resource $res The resource we will append the filters to |
305
|
|
|
* @param \AppserverIo\Doppelgaenger\Interfaces\StructureDefinitionInterface $structureDefinition Structure definition providing needed information |
306
|
|
|
* |
307
|
|
|
* @return array |
308
|
|
|
*/ |
309
|
|
|
protected function appendDefaultFilters( |
310
|
|
|
& $res, |
311
|
|
|
StructureDefinitionInterface $structureDefinition |
312
|
|
|
) { |
313
|
|
|
// resulting array with resources of appended filters |
314
|
|
|
$filters = array(); |
315
|
|
|
|
316
|
|
|
// Lets get the enforcement level |
317
|
|
|
$levelArray = array(); |
318
|
|
|
if ($this->config->hasValue('enforcement/level')) { |
319
|
|
|
$levelArray = array_reverse(str_split(decbin($this->config->getValue('enforcement/level')))); |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
// Whatever the enforcement level is, we will always need the skeleton filter. |
323
|
|
|
$filters['SkeletonFilter'] = $this->appendFilter( |
324
|
|
|
$res, |
325
|
|
|
'AppserverIo\Doppelgaenger\StreamFilters\SkeletonFilter', |
326
|
|
|
$structureDefinition |
327
|
|
|
); |
328
|
|
|
|
329
|
|
|
// Now lets register and append the filters if they are mapped to a 1 |
330
|
|
|
// Lets have a look at the precondition filter first |
331
|
|
View Code Duplication |
if (isset($levelArray[0]) && $levelArray[0] == 1) { |
332
|
|
|
// Do we even got any preconditions? |
333
|
|
|
$filterNeeded = false; |
334
|
|
|
$iterator = $structureDefinition->getFunctionDefinitions()->getIterator(); |
335
|
|
|
foreach ($iterator as $functionDefinition) { |
336
|
|
|
if ($functionDefinition->getAllPreconditions()->count() !== 0) { |
337
|
|
|
$filterNeeded = true; |
338
|
|
|
break; |
339
|
|
|
} |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
if ($filterNeeded) { |
343
|
|
|
$filters['PreconditionFilter'] = $this->appendFilter( |
344
|
|
|
$res, |
345
|
|
|
'AppserverIo\Doppelgaenger\StreamFilters\PreconditionFilter', |
346
|
|
|
$structureDefinition->getFunctionDefinitions() |
347
|
|
|
); |
348
|
|
|
} |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
// What about the post-condition filter? |
352
|
|
View Code Duplication |
if (isset($levelArray[1]) && $levelArray[1] == 1) { |
353
|
|
|
// Do we even got any post-conditions? |
354
|
|
|
$filterNeeded = false; |
355
|
|
|
$iterator = $structureDefinition->getFunctionDefinitions()->getIterator(); |
356
|
|
|
foreach ($iterator as $functionDefinition) { |
357
|
|
|
if ($functionDefinition->getAllPostconditions()->count() !== 0) { |
358
|
|
|
$filterNeeded = true; |
359
|
|
|
break; |
360
|
|
|
} |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
if ($filterNeeded) { |
364
|
|
|
$filters['PostconditionFilter'] = $this->appendFilter( |
365
|
|
|
$res, |
366
|
|
|
'AppserverIo\Doppelgaenger\StreamFilters\PostconditionFilter', |
367
|
|
|
$structureDefinition->getFunctionDefinitions() |
368
|
|
|
); |
369
|
|
|
} |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
// What about the invariant filter? |
373
|
|
|
if (isset($levelArray[2]) && $levelArray[2] == 1) { |
374
|
|
|
// Do we even got any invariants? |
375
|
|
|
if ($structureDefinition->getInvariants()->count(true) !== 0) { |
376
|
|
|
$filters['InvariantFilter'] = $this->appendFilter( |
377
|
|
|
$res, |
378
|
|
|
'AppserverIo\Doppelgaenger\StreamFilters\InvariantFilter', |
379
|
|
|
$structureDefinition |
380
|
|
|
); |
381
|
|
|
} |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
// introductions make only sense for classes |
385
|
|
|
if ($structureDefinition instanceof ClassDefinition) { |
386
|
|
|
// add the filter used for introductions |
387
|
|
|
$filters['IntroductionFilter'] = $this->appendFilter( |
388
|
|
|
$res, |
389
|
|
|
'AppserverIo\Doppelgaenger\StreamFilters\IntroductionFilter', |
390
|
|
|
$structureDefinition->getIntroductions() |
391
|
|
|
); |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
// add the filter we need for our AOP advices |
395
|
|
|
$filters['AdviceFilter'] = $this->appendFilter( |
396
|
|
|
$res, |
397
|
|
|
'AppserverIo\Doppelgaenger\StreamFilters\AdviceFilter', |
398
|
|
|
array('functionDefinitions' => $structureDefinition->getFunctionDefinitions(), 'aspectRegister' => $this->aspectRegister) |
399
|
|
|
); |
400
|
|
|
|
401
|
|
|
// add the filter used to proxy to the actual implementation |
402
|
|
|
$filters['ProcessingFilter'] = $this->appendFilter( |
403
|
|
|
$res, |
404
|
|
|
'AppserverIo\Doppelgaenger\StreamFilters\ProcessingFilter', |
405
|
|
|
$structureDefinition->getFunctionDefinitions() |
406
|
|
|
); |
407
|
|
|
|
408
|
|
|
// We ALWAYS need the enforcement filter. Everything else would not make any sense |
409
|
|
|
$filters['EnforcementFilter'] = $this->appendFilter( |
410
|
|
|
$res, |
411
|
|
|
'AppserverIo\Doppelgaenger\StreamFilters\EnforcementFilter', |
412
|
|
|
array('structureDefinition' => $structureDefinition, 'config' => $this->config) |
413
|
|
|
); |
414
|
|
|
|
415
|
|
|
// at last we want to make the output beatiful and detect sysntax errors |
416
|
|
|
// $filters['BeautifyFilter'] = $this->appendFilter($res, 'AppserverIo\Doppelgaenger\StreamFilters\BeautifyFilter', array()); |
417
|
|
|
|
418
|
|
|
return $filters; |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
/** |
422
|
|
|
* Will append a given filter to a resource. |
423
|
|
|
* Might fail if the filter cannot be found. |
424
|
|
|
* Will return true if filter got appended successfully |
425
|
|
|
* |
426
|
|
|
* @param resource $res The resource we will append the filters to |
427
|
|
|
* @param string $filterClass The fully qualified name of the filter class |
428
|
|
|
* @param mixed $params Whatever params the filter might need |
429
|
|
|
* |
430
|
|
|
* @return resource |
431
|
|
|
* |
432
|
|
|
* @throws \AppserverIo\Doppelgaenger\Exceptions\GeneratorException |
433
|
|
|
*/ |
434
|
|
|
public function appendFilter(& $res, $filterClass, $params) |
435
|
|
|
{ |
436
|
|
|
// check if the given filter exists and throw an exception if not |
437
|
|
|
if (!class_exists($filterClass)) { |
438
|
|
|
throw new GeneratorException(sprintf('Could not find filter class %s', $filterClass)); |
439
|
|
|
} |
440
|
|
|
|
441
|
|
|
// append the filter to the given resource |
442
|
|
|
$filterName = substr(strrchr($filterClass, '\\'), 1); |
443
|
|
|
stream_filter_register($filterName, $filterClass); |
444
|
|
|
return stream_filter_append( |
445
|
|
|
$res, |
446
|
|
|
$filterName, |
447
|
|
|
STREAM_FILTER_WRITE, |
448
|
|
|
$params |
449
|
|
|
); |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
/** |
453
|
|
|
* Return the cache path (as organized by our cache map) for a given structure name |
454
|
|
|
* |
455
|
|
|
* @param string $structureName The structure we want the cache path for |
456
|
|
|
* |
457
|
|
|
* @return boolean|string |
458
|
|
|
*/ |
459
|
|
|
public function getFileName($structureName) |
460
|
|
|
{ |
461
|
|
|
$mapEntry = $this->cacheMap->getEntry($structureName); |
462
|
|
|
|
463
|
|
|
if (!$mapEntry instanceof Structure) { |
464
|
|
|
// we should fail if we do not get a structure |
465
|
|
|
return false; |
466
|
|
|
} |
467
|
|
|
|
468
|
|
|
return $mapEntry->getPath(); |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
/** |
472
|
|
|
* Method used to update certain structures |
473
|
|
|
* |
474
|
|
|
* @param string $structureName Name of the structure we want to update |
475
|
|
|
* |
476
|
|
|
* @return boolean |
477
|
|
|
*/ |
478
|
|
|
public function update($structureName) |
479
|
|
|
{ |
480
|
|
|
return $this->create($structureName, true); |
|
|
|
|
481
|
|
|
} |
482
|
|
|
} |
483
|
|
|
|
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.