This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * \AppserverIo\Doppelgaenger\Parser\ClassParser |
||
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\Parser; |
||
22 | |||
23 | use AppserverIo\Doppelgaenger\Entities\Definitions\ClassDefinition; |
||
24 | use AppserverIo\Doppelgaenger\Entities\Definitions\Structure; |
||
25 | use AppserverIo\Doppelgaenger\Entities\Introduction; |
||
26 | use AppserverIo\Doppelgaenger\Entities\Lists\IntroductionList; |
||
27 | use AppserverIo\Doppelgaenger\Exceptions\GeneratorException; |
||
28 | use AppserverIo\Psr\MetaobjectProtocol\Aop\Annotations\Introduce; |
||
29 | use AppserverIo\Psr\MetaobjectProtocol\Dbc\Annotations\Invariant; |
||
30 | |||
31 | /** |
||
32 | * This class implements the StructureParserInterface for class structures |
||
33 | * |
||
34 | * @author Bernhard Wick <[email protected]> |
||
35 | * @copyright 2015 TechDivision GmbH - <[email protected]> |
||
36 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
||
37 | * @link https://github.com/appserver-io/doppelgaenger |
||
38 | * @link http://www.appserver.io/ |
||
39 | */ |
||
40 | class ClassParser extends AbstractStructureParser |
||
41 | { |
||
42 | |||
43 | /** |
||
44 | * We want to be able to parse properties |
||
45 | */ |
||
46 | use PropertyParserTrait; |
||
47 | |||
48 | /** |
||
49 | * Token representing the structure this parser is used for |
||
50 | * |
||
51 | * @var integer TOKEN |
||
52 | */ |
||
53 | const TOKEN = T_CLASS; |
||
54 | |||
55 | /** |
||
56 | * Will return the token representing the structure the parser is used for e.g. T_CLASS |
||
57 | * |
||
58 | * @return integer |
||
59 | */ |
||
60 | public function getToken() |
||
61 | { |
||
62 | return self::TOKEN; |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * Returns a ClassDefinition from a token array. |
||
67 | * |
||
68 | * This method will use a set of other methods to parse a token array and retrieve any |
||
69 | * possible information from it. This information will be entered into a ClassDefinition object. |
||
70 | * |
||
71 | * @param array $tokens The token array containing structure tokens |
||
72 | * @param boolean $getRecursive Do we have to get the ancestral conditions as well? |
||
73 | * |
||
74 | * @return \AppserverIo\Doppelgaenger\Interfaces\StructureDefinitionInterface |
||
75 | * |
||
76 | * @throws \AppserverIo\Doppelgaenger\Exceptions\GeneratorException |
||
77 | */ |
||
78 | protected function getDefinitionFromTokens($tokens, $getRecursive = true) |
||
79 | { |
||
80 | // First of all we need a new ClassDefinition to fill |
||
81 | View Code Duplication | if (is_null($this->currentDefinition)) { |
|
82 | $this->currentDefinition = new ClassDefinition(); |
||
83 | |||
0 ignored issues
–
show
Coding Style
introduced
by
![]() |
|||
84 | } elseif (!$this->currentDefinition instanceof ClassDefinition) { |
||
85 | throw new GeneratorException(sprintf( |
||
86 | 'The structure definition %s does not seem to be a class definition.', |
||
87 | $this->currentDefinition->getQualifiedName() |
||
88 | )); |
||
89 | } |
||
90 | |||
91 | // Save the path of the original definition for later use |
||
92 | $this->currentDefinition->setPath($this->file); |
||
93 | |||
94 | // File based namespaces do not make much sense, so hand it over here. |
||
95 | $this->currentDefinition->setNamespace($this->getNamespace()); |
||
96 | $this->currentDefinition->setName($this->getName($tokens)); |
||
97 | $this->currentDefinition->setUsedStructures($this->getUsedStructures()); |
||
98 | |||
99 | // For our next step we would like to get the doc comment (if any) |
||
100 | $this->currentDefinition->setDocBlock($this->getDocBlock($tokens, self::TOKEN)); |
||
101 | |||
102 | // Get start and end line |
||
103 | $this->currentDefinition->setStartLine($this->getStartLine($tokens)); |
||
104 | $this->currentDefinition->setEndLine($this->getEndLine($tokens)); |
||
105 | |||
106 | // Lets get the attributes the class might have |
||
107 | $this->currentDefinition->setAttributeDefinitions($this->getAttributes( |
||
108 | $tokens |
||
109 | )); |
||
110 | |||
111 | // So we got our docBlock, now we can parse the invariant annotations from it |
||
112 | $annotationParser = new AnnotationParser($this->file, $this->config, $this->tokens, $this->currentDefinition); |
||
113 | $invariantConditions = $annotationParser->getConditions( |
||
114 | $this->currentDefinition->getDocBlock(), |
||
115 | Invariant::ANNOTATION |
||
116 | ); |
||
117 | if (!is_bool($invariantConditions)) { |
||
118 | $this->currentDefinition->setInvariantConditions($invariantConditions); |
||
119 | } |
||
120 | |||
121 | // we would be also interested in introductions |
||
122 | $introductions = new IntroductionList(); |
||
123 | $introductionAnnotations = $annotationParser->getAnnotationsByType( |
||
124 | $this->currentDefinition->getDocBlock(), |
||
125 | Introduce::ANNOTATION |
||
126 | ); |
||
127 | foreach ($introductionAnnotations as $introductionAnnotation) { |
||
128 | $introduction = new Introduction(); |
||
129 | $introduction->setTarget($this->currentDefinition->getQualifiedName()); |
||
130 | $introduction->setImplementation($introductionAnnotation->values['implementation']); |
||
131 | $introduction->setInterface($introductionAnnotation->values['interface']); |
||
132 | |||
133 | $introductions->add($introduction); |
||
134 | } |
||
135 | |||
136 | $this->currentDefinition->setIntroductions($introductions); |
||
137 | |||
138 | // Get the class identity |
||
139 | $this->currentDefinition->setIsFinal($this->hasSignatureToken($this->tokens, T_FINAL, self::TOKEN)); |
||
140 | $this->currentDefinition->setIsAbstract($this->hasSignatureToken($this->tokens, T_ABSTRACT, self::TOKEN)); |
||
141 | |||
142 | // Lets check if there is any inheritance, or if we implement any interfaces |
||
143 | $this->currentDefinition->setExtends(trim( |
||
144 | $this->resolveUsedNamespace( |
||
145 | $this->currentDefinition, |
||
146 | $this->getParent($tokens) |
||
147 | ), |
||
148 | '\\' |
||
149 | )); |
||
150 | // Get all the interfaces we have |
||
151 | $this->currentDefinition->setImplements($this->getInterfaces($this->currentDefinition)); |
||
0 ignored issues
–
show
$this->currentDefinition of type object<AppserverIo\Doppe...ureDefinitionInterface> is not a sub-type of object<AppserverIo\Doppe...itions\ClassDefinition> . It seems like you assume a concrete implementation of the interface AppserverIo\Doppelgaenge...tureDefinitionInterface to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type. ![]() It seems like you code against a concrete implementation and not the interface
AppserverIo\Doppelgaenge...tureDefinitionInterface as the method setImplements() does only exist in the following implementations of said interface: AppserverIo\Doppelgaenge...itions\AspectDefinition , AppserverIo\Doppelgaenge...nitions\ClassDefinition .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
152 | |||
153 | // Get all class constants |
||
154 | $this->currentDefinition->setConstants($this->getConstants($tokens)); |
||
0 ignored issues
–
show
The call to
ClassParser::getConstants() has too many arguments starting with $tokens .
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 ![]() |
|||
155 | |||
156 | // Only thing still missing are the methods, so ramp up our FunctionParser |
||
157 | $functionParser = new FunctionParser( |
||
158 | $this->file, |
||
159 | $this->config, |
||
160 | $this->structureDefinitionHierarchy, |
||
161 | $this->structureMap, |
||
162 | $this->currentDefinition, |
||
163 | $this->tokens |
||
164 | ); |
||
165 | |||
166 | $functionDefinitions = $functionParser->getDefinitionListFromTokens( |
||
167 | $tokens, |
||
168 | $getRecursive |
||
169 | ); |
||
170 | if ($functionDefinitions !== false) { |
||
171 | $this->currentDefinition->setFunctionDefinitions($functionDefinitions); |
||
172 | } |
||
173 | |||
174 | // If we have to parse the definition in a recursive manner, we have to get the parent invariants |
||
175 | if ($getRecursive === true) { |
||
176 | // Add all the assertions we might get from ancestral dependencies |
||
177 | $this->addAncestralAssertions($this->currentDefinition); |
||
178 | } |
||
179 | |||
180 | // Lets get the attributes the class might have |
||
181 | $this->currentDefinition->setAttributeDefinitions($this->getAttributes( |
||
182 | $tokens, |
||
183 | $this->currentDefinition->getInvariants() |
||
184 | )); |
||
185 | |||
186 | // Before exiting we will add the entry to the current structure definition hierarchy |
||
187 | $this->structureDefinitionHierarchy->insert($this->currentDefinition); |
||
188 | |||
189 | return $this->currentDefinition; |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * This method will add all assertions any ancestral structures (parent classes, implemented interfaces) might have |
||
194 | * to the passed class definition. |
||
195 | * |
||
196 | * @param \AppserverIo\Doppelgaenger\Entities\Definitions\ClassDefinition $classDefinition The class definition we have to |
||
197 | * add the assertions to |
||
198 | * |
||
199 | * @return null |
||
200 | */ |
||
201 | protected function addAncestralAssertions(ClassDefinition $classDefinition) |
||
202 | { |
||
203 | $dependencies = $classDefinition->getDependencies(); |
||
204 | foreach ($dependencies as $dependency) { |
||
205 | // freshly set the dependency definition to avoid side effects |
||
206 | $dependencyDefinition = null; |
||
0 ignored issues
–
show
$dependencyDefinition is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
207 | |||
208 | $fileEntry = $this->structureMap->getEntry($dependency); |
||
209 | if (!$fileEntry instanceof Structure) { |
||
210 | // Continue, don't fail as we might have dependencies which are not under Doppelgaenger surveillance |
||
211 | continue; |
||
212 | } |
||
213 | |||
214 | // Get the needed parser |
||
215 | $structureParserFactory = new StructureParserFactory(); |
||
216 | $parser = $structureParserFactory->getInstance( |
||
217 | $fileEntry->getType(), |
||
218 | $fileEntry->getPath(), |
||
219 | $this->config, |
||
220 | $this->structureMap, |
||
221 | $this->structureDefinitionHierarchy |
||
222 | ); |
||
223 | |||
224 | // Get the definition |
||
225 | $dependencyDefinition = $parser->getDefinition( |
||
226 | $dependency, |
||
227 | true |
||
228 | ); |
||
229 | |||
230 | // Only classes and traits have invariants |
||
231 | if ($fileEntry->getType() === 'class') { |
||
232 | $classDefinition->setAncestralInvariants($dependencyDefinition->getInvariants(true)); |
||
233 | } |
||
234 | |||
235 | // Finally add the dependency definition to our structure definition hierarchy to avoid |
||
236 | // redundant parsing |
||
237 | $this->structureDefinitionHierarchy->insert($dependencyDefinition); |
||
238 | } |
||
239 | } |
||
240 | |||
241 | /** |
||
242 | * Will find the parent class we have (if any). Will return an empty string if there is none. |
||
243 | * |
||
244 | * @param array $tokens Array of tokens for this class |
||
245 | * |
||
246 | * @return string |
||
247 | */ |
||
248 | protected function getParent(array $tokens) |
||
249 | { |
||
250 | // Check the tokens |
||
251 | $className = ''; |
||
252 | for ($i = 0; $i < count($tokens); $i++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
253 | // If we got the class name |
||
254 | if ($tokens[$i][0] === T_EXTENDS) { |
||
255 | for ($j = $i + 1; $j < count($tokens); $j++) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
256 | if ($tokens[$j] === '{' || $tokens[$j][0] === T_CURLY_OPEN || $tokens[$j][0] === T_IMPLEMENTS) { |
||
257 | return $className; |
||
258 | |||
0 ignored issues
–
show
|
|||
259 | } elseif ($tokens[$j][0] === T_STRING) { |
||
260 | $className .= $tokens[$j][1]; |
||
261 | } |
||
262 | } |
||
263 | } |
||
264 | } |
||
265 | |||
266 | // Return what we did or did not found |
||
267 | return $className; |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * Will return an array containing all interfaces this class implements |
||
272 | * |
||
273 | * @param ClassDefinition $classDefinition Reference of class definition so we can resolve the namespaces |
||
274 | * |
||
275 | * @return array |
||
276 | */ |
||
277 | protected function getInterfaces(ClassDefinition & $classDefinition) |
||
278 | { |
||
279 | // Check the tokens |
||
280 | $interfaces = array(); |
||
281 | for ($i = 0; $i < $this->tokenCount; $i++) { |
||
282 | // If we got the class name |
||
283 | if ($this->tokens[$i][0] === T_IMPLEMENTS) { |
||
284 | for ($j = $i + 1; $j < $this->tokenCount; $j++) { |
||
285 | if ($this->tokens[$j] === '{' || $this->tokens[$j][0] === T_CURLY_OPEN || |
||
286 | $this->tokens[$j][0] === T_EXTENDS |
||
287 | ) { |
||
288 | return $interfaces; |
||
289 | |||
0 ignored issues
–
show
|
|||
290 | } elseif ($this->tokens[$j][0] === T_STRING) { |
||
291 | $interfaces[] = $this->resolveUsedNamespace( |
||
292 | $classDefinition, |
||
293 | $this->tokens[$j][1] |
||
294 | ); |
||
295 | } |
||
296 | } |
||
297 | } |
||
298 | } |
||
299 | |||
300 | // Return what we did or did not found |
||
301 | return $interfaces; |
||
302 | } |
||
303 | } |
||
304 |