• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

voku / Simple-PHP-Code-Parser / 5703591739

pending completion
5703591739

push

github

voku
Merge branch 'master' of ssh://github.com/voku/Simple-PHP-Code-Parser

* 'master' of ssh://github.com/voku/Simple-PHP-Code-Parser:
  Update actions/cache action to v3
  Apply fixes from StyleCI
  Update codecov/codecov-action action to v3
  Update shivammathur/setup-php action to v2.24.0
  Update actions/cache action to v2.1.8

3 of 3 new or added lines in 1 file covered. (100.0%)

1293 of 1572 relevant lines covered (82.25%)

20.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.69
/src/voku/SimplePhpParser/Model/PHPParameter.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace voku\SimplePhpParser\Model;
6

7
use PhpParser\Comment\Doc;
8
use PhpParser\Node\FunctionLike;
9
use PhpParser\Node\Param;
10
use ReflectionParameter;
11
use voku\SimplePhpParser\Parsers\Helper\Utils;
12

13
class PHPParameter extends BasePHPElement
14
{
15
    /**
16
     * @var mixed|null
17
     */
18
    public $defaultValue;
19

20
    /**
21
     * @var string|null
22
     */
23
    public $phpDocRaw;
24

25
    /**
26
     * @var string|null
27
     */
28
    public $type;
29

30
    /**
31
     * @var string|null
32
     */
33
    public $typeFromDefaultValue;
34

35
    /**
36
     * @var string|null
37
     */
38
    public $typeFromPhpDoc;
39

40
    /**
41
     * @var string|null
42
     */
43
    public $typeFromPhpDocSimple;
44

45
    /**
46
     * @var string|null
47
     */
48
    public $typeFromPhpDocExtended;
49

50
    /**
51
     * @var string|null
52
     */
53
    public $typeFromPhpDocMaybeWithComment;
54

55
    /**
56
     * @var bool|null
57
     */
58
    public $is_vararg;
59

60
    /**
61
     * @var bool|null
62
     */
63
    public $is_passed_by_ref;
64

65
    /**
66
     * @var bool|null
67
     */
68
    public $is_inheritdoc;
69

70
    /**
71
     * @param Param        $parameter
72
     * @param FunctionLike $node
73
     * @param mixed|null   $classStr
74
     *
75
     * @return $this
76
     */
77
    public function readObjectFromPhpNode($parameter, $node = null, $classStr = null): self
78
    {
79
        $parameterVar = $parameter->var;
38✔
80
        if ($parameterVar instanceof \PhpParser\Node\Expr\Error) {
38✔
81
            $this->parseError[] = ($this->line ?? '?') . ':' . ($this->pos ?? '') . ' | may be at this position an expression is required';
×
82

83
            $this->name = \md5(\uniqid('error', true));
×
84

85
            return $this;
×
86
        }
87

88
        $this->name = \is_string($parameterVar->name) ? $parameterVar->name : '';
38✔
89

90
        if ($node) {
38✔
91
            $this->prepareNode($node);
38✔
92

93
            $docComment = $node->getDocComment();
38✔
94
            if ($docComment) {
38✔
95
                $docCommentText = $docComment->getText();
35✔
96

97
                if (\stripos($docCommentText, '@inheritdoc') !== false) {
35✔
98
                    $this->is_inheritdoc = true;
17✔
99
                }
100

101
                $this->readPhpDoc($docComment, $this->name);
35✔
102
            }
103
        }
104

105
        if ($parameter->type !== null) {
38✔
106
            if (!$this->type) {
23✔
107
                if (empty($parameter->type->name)) {
6✔
108
                    if (!empty($parameter->type->parts)) {
×
109
                        $this->type = '\\' . \implode('\\', $parameter->type->parts);
×
110
                    }
111
                } else {
112
                    $this->type = $parameter->type->name;
6✔
113
                }
114
            }
115

116
            if ($parameter->type instanceof \PhpParser\Node\NullableType) {
23✔
117
                if ($this->type && $this->type !== 'null' && \strpos($this->type, 'null|') !== 0) {
6✔
118
                    $this->type = 'null|' . $this->type;
×
119
                } elseif (!$this->type) {
6✔
120
                    $this->type = 'null|mixed';
×
121
                }
122
            }
123
        }
124

125
        if ($parameter->default) {
38✔
126
            $defaultValue = Utils::getPhpParserValueFromNode($parameter->default, $classStr, $this->parserContainer);
21✔
127
            if ($defaultValue !== Utils::GET_PHP_PARSER_VALUE_FROM_NODE_HELPER) {
21✔
128
                $this->defaultValue = $defaultValue;
21✔
129

130
                $this->typeFromDefaultValue = Utils::normalizePhpType(\gettype($this->defaultValue));
21✔
131
            }
132
        }
133

134
        $this->is_vararg = $parameter->variadic;
38✔
135

136
        $this->is_passed_by_ref = $parameter->byRef;
38✔
137

138
        return $this;
38✔
139
    }
140

141
    /**
142
     * @param ReflectionParameter $parameter
143
     *
144
     * @return $this
145
     */
146
    public function readObjectFromReflection($parameter): self
147
    {
148
        $this->name = $parameter->getName();
38✔
149

150
        if ($parameter->isDefaultValueAvailable()) {
38✔
151
            try {
152
                $this->defaultValue = $parameter->getDefaultValue();
23✔
153
            } catch (\ReflectionException $e) {
×
154
                // nothing
155
            }
156
            if ($this->defaultValue !== null) {
23✔
157
                $this->typeFromDefaultValue = Utils::normalizePhpType(\gettype($this->defaultValue));
23✔
158
            }
159
        }
160

161
        $method = $parameter->getDeclaringFunction();
38✔
162

163
        $docComment = $method->getDocComment();
38✔
164
        if ($docComment) {
38✔
165
            if (\stripos($docComment, '@inheritdoc') !== false) {
32✔
166
                $this->is_inheritdoc = true;
17✔
167
            }
168

169
            $this->readPhpDoc($docComment, $this->name);
32✔
170
        }
171

172
        try {
173
            $type = $parameter->getType();
38✔
174
        } catch (\ReflectionException $e) {
×
175
            $type = null;
×
176
        }
177
        if ($type !== null) {
38✔
178
            if (\method_exists($type, 'getName')) {
37✔
179
                $this->type = Utils::normalizePhpType($type->getName(), true);
37✔
180
            } else {
181
                $this->type = Utils::normalizePhpType($type . '', true);
4✔
182
            }
183
            if ($this->type && \class_exists($this->type, false)) {
37✔
184
                $this->type = '\\' . \ltrim($this->type, '\\');
33✔
185
            }
186

187
            try {
188
                $constNameTmp = $parameter->getDefaultValueConstantName();
37✔
189
                if ($constNameTmp && \defined($constNameTmp)) {
23✔
190
                    $defaultTmp = \constant($constNameTmp);
6✔
191
                    if ($defaultTmp === null) {
6✔
192
                        if ($this->type && $this->type !== 'null' && \strpos($this->type, 'null|') !== 0) {
×
193
                            $this->type = 'null|' . $this->type;
×
194
                        } elseif (!$this->type) {
×
195
                            $this->type = 'null|mixed';
23✔
196
                        }
197
                    }
198
                }
199
            } catch (\ReflectionException $e) {
37✔
200
                if ($type->allowsNull()) {
37✔
201
                    if ($this->type && $this->type !== 'null' && \strpos($this->type, 'null|') !== 0) {
6✔
202
                        $this->type = 'null|' . $this->type;
6✔
203
                    } elseif (!$this->type) {
×
204
                        $this->type = 'null|mixed';
×
205
                    }
206
                }
207
            }
208
        }
209

210
        $this->is_vararg = $parameter->isVariadic();
38✔
211

212
        $this->is_passed_by_ref = $parameter->isPassedByReference();
38✔
213

214
        return $this;
38✔
215
    }
216

217
    /**
218
     * @return string|null
219
     */
220
    public function getType(): ?string
221
    {
222
        if ($this->typeFromPhpDocExtended) {
×
223
            return $this->typeFromPhpDocExtended;
×
224
        }
225

226
        if ($this->type) {
×
227
            return $this->type;
×
228
        }
229

230
        if ($this->typeFromPhpDocSimple) {
×
231
            return $this->typeFromPhpDocSimple;
×
232
        }
233

234
        return null;
×
235
    }
236

237
    /**
238
     * @param Doc|string $doc
239
     */
240
    private function readPhpDoc($doc, string $parameterName): void
241
    {
242
        if ($doc instanceof Doc) {
38✔
243
            $docComment = $doc->getText();
35✔
244
        } else {
245
            $docComment = $doc;
32✔
246
        }
247
        if ($docComment === '') {
38✔
248
            return;
×
249
        }
250

251
        try {
252
            $phpDoc = Utils::createDocBlockInstance()->create($docComment);
38✔
253

254
            $parsedParamTags = $phpDoc->getTagsByName('param');
38✔
255

256
            if (!empty($parsedParamTags)) {
38✔
257
                foreach ($parsedParamTags as $parsedParamTag) {
35✔
258
                    if ($parsedParamTag instanceof \phpDocumentor\Reflection\DocBlock\Tags\Param) {
35✔
259
                        // check only the current "param"-tag
260
                        if (\strtoupper($parameterName) !== \strtoupper((string) $parsedParamTag->getVariableName())) {
35✔
261
                            continue;
32✔
262
                        }
263

264
                        $type = $parsedParamTag->getType();
35✔
265

266
                        $this->typeFromPhpDoc = Utils::normalizePhpType($type . '');
35✔
267

268
                        $typeFromPhpDocMaybeWithCommentTmp = \trim((string) $parsedParamTag);
35✔
269
                        if (
270
                            $typeFromPhpDocMaybeWithCommentTmp
35✔
271
                            &&
272
                            \strpos($typeFromPhpDocMaybeWithCommentTmp, '$') !== 0
35✔
273
                        ) {
274
                            $this->typeFromPhpDocMaybeWithComment = $typeFromPhpDocMaybeWithCommentTmp;
35✔
275
                        }
276

277
                        $typeTmp = Utils::parseDocTypeObject($type);
35✔
278
                        if ($typeTmp !== '') {
35✔
279
                            $this->typeFromPhpDocSimple = $typeTmp;
35✔
280
                        }
281
                    }
282

283
                    $parsedParamTagParam = (string) $parsedParamTag;
35✔
284
                    $spitedData = Utils::splitTypeAndVariable($parsedParamTag);
35✔
285
                    $parsedParamTagStr = $spitedData['parsedParamTagStr'];
35✔
286
                    $variableName = $spitedData['variableName'];
35✔
287

288
                    // check only the current "param"-tag
289
                    if ($variableName && \strtoupper($parameterName) === \strtoupper($variableName)) {
35✔
290
                        $this->phpDocRaw = (string) $parsedParamTag;
35✔
291
                        $this->typeFromPhpDocExtended = Utils::modernPhpdoc($parsedParamTagParam);
35✔
292
                    }
293
                }
294
            }
295

296
            $parsedParamTags = $phpDoc->getTagsByName('psalm-param')
38✔
297
                               + $phpDoc->getTagsByName('phpstan-param');
38✔
298

299
            if (!empty($parsedParamTags)) {
38✔
300
                foreach ($parsedParamTags as $parsedParamTag) {
18✔
301
                    if ($parsedParamTag instanceof \phpDocumentor\Reflection\DocBlock\Tags\Generic) {
18✔
302
                        $spitedData = Utils::splitTypeAndVariable($parsedParamTag);
18✔
303
                        $parsedParamTagStr = $spitedData['parsedParamTagStr'];
18✔
304
                        $variableName = $spitedData['variableName'];
18✔
305

306
                        // check only the current "param"-tag
307
                        if (!$variableName || \strtoupper($parameterName) !== \strtoupper($variableName)) {
18✔
308
                            continue;
18✔
309
                        }
310

311
                        $this->typeFromPhpDocExtended = Utils::modernPhpdoc($parsedParamTagStr);
18✔
312
                    }
313
                }
314
            }
315

316
            if (
317
                $doc instanceof Doc
38✔
318
                &&
319
                !$this->phpDocRaw
38✔
320
            ) {
321
                $tokens = Utils::modernPhpdocTokens($doc->getText());
32✔
322

323
                $paramTagFound = null;
32✔
324
                $paramContent = '';
32✔
325
                foreach ($tokens->getTokens() as $token) {
32✔
326
                    $content = $token[0] ?? '';
32✔
327

328
                    if ($content === '@param' || $content === '@psalm-param' || $content === '@phpstan-param') {
32✔
329
                        $paramContent = '';
17✔
330
                        $paramTagFound = true;
17✔
331

332
                        continue;
17✔
333
                    }
334

335
                    if ($content === '$' . $parameterName) {
32✔
336
                        break;
17✔
337
                    }
338

339
                    if (\strpos($content, '$') === 0) {
32✔
340
                        $paramContent = '';
2✔
341
                        $paramTagFound = false;
2✔
342
                    }
343

344
                    if ($paramTagFound) {
32✔
345
                        $paramContent .= $content;
17✔
346
                    }
347
                }
348

349
                $paramContent = \trim($paramContent);
32✔
350
                if ($paramContent) {
32✔
351
                    $this->typeFromPhpDocExtended = Utils::modernPhpdoc($paramContent);
38✔
352
                }
353
            }
354
        } catch (\Exception $e) {
23✔
355
            $tmpErrorMessage = $this->name . ':' . ($this->line ?? '?') . ' | ' . \print_r($e->getMessage(), true);
23✔
356
            $this->parseError[\md5($tmpErrorMessage)] = $tmpErrorMessage;
23✔
357
        }
358
    }
359
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc