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 | declare(strict_types = 1); |
||
4 | |||
5 | namespace Leaditin\Annotations\Reader; |
||
6 | |||
7 | use Leaditin\Annotations\Annotation; |
||
8 | use Leaditin\Annotations\Collection; |
||
9 | use Leaditin\Annotations\Exception\ReaderException; |
||
10 | use Leaditin\Annotations\Reflection; |
||
11 | use Leaditin\Annotations\Tokenizer; |
||
12 | |||
13 | /** |
||
14 | * Class ReflectionReader |
||
15 | * |
||
16 | * @package Leaditin\Annotations |
||
17 | * @author Igor Vuckovic <[email protected]> |
||
18 | */ |
||
19 | class ReflectionReader implements ReaderInterface |
||
20 | { |
||
21 | /** @var \ReflectionClass */ |
||
22 | protected $reflectionClass; |
||
23 | |||
24 | /** @var Tokenizer */ |
||
25 | protected $tokenizer; |
||
26 | |||
27 | /** |
||
28 | * @param string $class |
||
29 | * @return Reflection |
||
30 | * @throws ReaderException |
||
31 | */ |
||
32 | 8 | public function read(string $class) : Reflection |
|
33 | { |
||
34 | try { |
||
35 | 8 | $this->reflectionClass = new \ReflectionClass($class); |
|
36 | 7 | $this->tokenizer = new Tokenizer($this->reflectionClass); |
|
37 | |||
38 | 7 | return new Reflection( |
|
39 | 7 | $this->readAnnotationsFromClass(), |
|
40 | 7 | $this->readAnnotationsFromMethods(), |
|
41 | 7 | $this->readAnnotationsFromProperties() |
|
42 | ); |
||
43 | 1 | } catch (\ReflectionException $ex) { |
|
44 | 1 | throw ReaderException::unableToReadClass($class, $ex); |
|
45 | } |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * @return Collection |
||
50 | */ |
||
51 | 7 | protected function readAnnotationsFromClass() : Collection |
|
52 | { |
||
53 | 7 | $collection = $this->parseComment($this->reflectionClass->getDocComment()); |
|
54 | |||
55 | 7 | return new Collection(...$collection); |
|
56 | } |
||
57 | |||
58 | /** |
||
59 | * @return array|Collection[] |
||
60 | */ |
||
61 | 7 | View Code Duplication | protected function readAnnotationsFromMethods() : array |
0 ignored issues
–
show
|
|||
62 | { |
||
63 | 7 | $annotationsFromMethods = []; |
|
64 | 7 | foreach ($this->reflectionClass->getMethods() as $method) { |
|
65 | 7 | $methodCollection = $this->parseComment($method->getDocComment()); |
|
66 | 7 | if (empty($methodCollection)) { |
|
67 | 7 | continue; |
|
68 | } |
||
69 | |||
70 | 7 | $annotationsFromMethods[$method->name] = new Collection(...$methodCollection); |
|
71 | } |
||
72 | |||
73 | 7 | return $annotationsFromMethods; |
|
74 | } |
||
75 | |||
76 | /** |
||
77 | * @return array|Collection[] |
||
78 | */ |
||
79 | 7 | View Code Duplication | protected function readAnnotationsFromProperties() : array |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
80 | { |
||
81 | 7 | $annotationsFromProperties = []; |
|
82 | 7 | foreach ($this->reflectionClass->getProperties() as $property) { |
|
83 | 7 | $propertyCollection = $this->parseComment($property->getDocComment()); |
|
84 | 7 | if (empty($propertyCollection)) { |
|
85 | 7 | continue; |
|
86 | } |
||
87 | |||
88 | 7 | $annotationsFromProperties[$property->name] = new Collection(...$propertyCollection); |
|
89 | } |
||
90 | |||
91 | 7 | return $annotationsFromProperties; |
|
92 | } |
||
93 | |||
94 | /** |
||
95 | * @param string|bool $comment |
||
96 | * @return array|Annotation[] |
||
97 | */ |
||
98 | 7 | protected function parseComment($comment = false) : array |
|
99 | { |
||
100 | 7 | $annotations = []; |
|
101 | |||
102 | 7 | if ($comment === false) { |
|
103 | 7 | return $annotations; |
|
104 | } |
||
105 | |||
106 | 7 | preg_match_all('/@([^*]+)/', $comment, $matches); |
|
107 | 7 | foreach ($matches[1] as $match) { |
|
108 | 7 | $annotations[] = $this->parseLine($match); |
|
109 | } |
||
110 | |||
111 | 7 | return $annotations; |
|
112 | } |
||
113 | |||
114 | /** |
||
115 | * @param string $line |
||
116 | * @return bool|Annotation |
||
117 | */ |
||
118 | 7 | protected function parseLine(string $line) |
|
119 | { |
||
120 | 7 | preg_match('/^(\w+)(\(.+\)|\s+.+\n*|\}?)/', $line, $matches); |
|
121 | 7 | $name = $matches[1]; |
|
122 | 7 | $arguments = $this->parseArgumentsFromLine($matches[2] ?: ''); |
|
123 | 7 | $this->filterArguments($name, $arguments); |
|
124 | |||
125 | 7 | return new Annotation($name, $arguments); |
|
126 | } |
||
127 | |||
128 | /** |
||
129 | * @param string $line |
||
130 | * @return array |
||
131 | */ |
||
132 | 7 | protected function parseArgumentsFromLine(string $line) : array |
|
133 | { |
||
134 | 7 | $line = preg_replace('/^\((.*?)\)$/', '$1', trim($line)); |
|
135 | 7 | $arguments = []; |
|
136 | |||
137 | 7 | if ($line === '') { |
|
138 | 7 | return $arguments; |
|
139 | } |
||
140 | |||
141 | 7 | $data = $this->exportArgumentsFromLine($line); |
|
142 | 7 | foreach ($data as $index => $property) { |
|
143 | 7 | $properties = explode('=', $property, 2); |
|
144 | 7 | if (count($properties) === 1) { |
|
145 | 7 | $arguments[$index] = $this->filterValue($property); |
|
146 | } else { |
||
147 | 7 | $arguments[$this->filterName($properties[0])] = $this->filterValue($properties[1]); |
|
148 | } |
||
149 | } |
||
150 | |||
151 | 7 | return $arguments; |
|
152 | } |
||
153 | |||
154 | /** |
||
155 | * @param string $line |
||
156 | * @return array |
||
157 | */ |
||
158 | 7 | protected function exportArgumentsFromLine(string $line) : array |
|
159 | { |
||
160 | 7 | if (false !== strpos($line, '|')) { |
|
161 | 7 | return explode('|', $line); |
|
162 | } |
||
163 | |||
164 | 7 | return explode(',', $line); |
|
165 | } |
||
166 | |||
167 | /** |
||
168 | * @param string $name |
||
169 | * @return string |
||
170 | */ |
||
171 | protected function filterName(string $name) : string |
||
172 | { |
||
173 | 7 | return preg_replace_callback('/^"([^"]*)"$|^\'([^\']*)\'$/', function ($matches) { |
|
174 | 7 | return $matches[2] ?? $matches[1]; |
|
175 | 7 | }, trim($name)); |
|
176 | } |
||
177 | |||
178 | /** |
||
179 | * @param string $value |
||
180 | * @return int|string|bool|float|array |
||
181 | */ |
||
182 | 7 | protected function filterValue(string $value) |
|
183 | { |
||
184 | 7 | $value = $this->filterName($value); |
|
185 | 7 | $data = json_decode(str_replace('\'', '"', $value), true); |
|
186 | |||
187 | 7 | return $data ?? $value; |
|
188 | } |
||
189 | |||
190 | /** |
||
191 | * @param string $name |
||
192 | * @param array $arguments |
||
193 | */ |
||
194 | 7 | protected function filterArguments(string $name, array &$arguments) |
|
195 | { |
||
196 | $allowed = [ |
||
197 | 7 | 'var', 'param', 'property', 'method', 'return', 'throws', |
|
198 | ]; |
||
199 | |||
200 | 7 | if (!in_array($name, $allowed, false)) { |
|
201 | 7 | return; |
|
202 | } |
||
203 | |||
204 | 7 | array_walk($arguments, function (&$val) { |
|
205 | 7 | $val = preg_replace('/(\$\w+)$/', '', $val); |
|
206 | 7 | $val = trim($val); |
|
207 | 7 | $val = $this->tokenizer->resolveVariableName($val); |
|
208 | 7 | $val = $this->tokenizer->resolveFullyQualifiedClassName($val); |
|
209 | 7 | }); |
|
210 | } |
||
211 | } |
||
212 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.