• 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

65.07
/src/voku/SimplePhpParser/Model/PHPTrait.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\Stmt\Trait_;
9
use ReflectionClass;
10
use voku\SimplePhpParser\Parsers\Helper\Utils;
11

12
final class PHPTrait extends BasePHPClass
13
{
14
    /**
15
     * @var string
16
     *
17
     * @phpstan-var class-string
18
     */
19
    public $name;
20

21
    /**
22
     * @param Trait_ $node
23
     * @param null   $dummy
24
     *
25
     * @return $this
26
     */
27
    public function readObjectFromPhpNode($node, $dummy = null): self
28
    {
29
        $this->prepareNode($node);
6✔
30

31
        $this->name = static::getFQN($node);
6✔
32

33
        if (\trait_exists($this->name, true)) {
6✔
34
            $reflectionClass = Utils::createClassReflectionInstance($this->name);
6✔
35
            $this->readObjectFromReflection($reflectionClass);
6✔
36
        }
37

38
        $this->collectTags($node);
6✔
39

40
        $docComment = $node->getDocComment();
6✔
41
        if ($docComment) {
6✔
42
            $this->readPhpDocProperties($docComment);
6✔
43
        }
44

45
        foreach ($node->getProperties() as $property) {
6✔
46
            $propertyNameTmp = $this->getConstantFQN($property, $property->props[0]->name->name);
6✔
47

48
            if (isset($this->properties[$propertyNameTmp])) {
6✔
49
                $this->properties[$propertyNameTmp] = $this->properties[$propertyNameTmp]->readObjectFromPhpNode($property, $this->name);
6✔
50
            } else {
51
                $this->properties[$propertyNameTmp] = (new PHPProperty($this->parserContainer))->readObjectFromPhpNode($property, $this->name);
×
52
            }
53
        }
54

55
        foreach ($node->getMethods() as $method) {
6✔
56
            $methodNameTmp = $method->name->name;
6✔
57

58
            if (isset($this->methods[$methodNameTmp])) {
6✔
59
                $this->methods[$methodNameTmp] = $this->methods[$methodNameTmp]->readObjectFromPhpNode($method, $this->name);
6✔
60
            } else {
61
                $this->methods[$methodNameTmp] = (new PHPMethod($this->parserContainer))->readObjectFromPhpNode($method, $this->name);
×
62
            }
63

64
            if (!$this->methods[$methodNameTmp]->file) {
6✔
65
                $this->methods[$methodNameTmp]->file = $this->file;
×
66
            }
67
        }
68

69
        return $this;
6✔
70
    }
71

72
    /**
73
     * @param ReflectionClass $clazz
74
     *
75
     * @return $this
76
     */
77
    public function readObjectFromReflection($clazz): self
78
    {
79
        if (!$clazz->isTrait()) {
6✔
80
            return $this;
×
81
        }
82

83
        $this->name = $clazz->getName();
6✔
84

85
        if (!$this->line) {
6✔
86
            $lineTmp = $clazz->getStartLine();
×
87
            if ($lineTmp !== false) {
×
88
                $this->line = $lineTmp;
×
89
            }
90
        }
91

92
        $file = $clazz->getFileName();
6✔
93
        if ($file) {
6✔
94
            $this->file = $file;
6✔
95
        }
96

97
        $this->is_final = $clazz->isFinal();
6✔
98

99
        $this->is_abstract = $clazz->isAbstract();
6✔
100

101
        $this->is_anonymous = $clazz->isAnonymous();
6✔
102

103
        $this->is_cloneable = $clazz->isCloneable();
6✔
104

105
        $this->is_instantiable = $clazz->isInstantiable();
6✔
106

107
        $this->is_iterable = $clazz->isIterable();
6✔
108

109
        foreach ($clazz->getProperties() as $property) {
6✔
110
            $propertyPhp = (new PHPProperty($this->parserContainer))->readObjectFromReflection($property);
6✔
111
            $this->properties[$propertyPhp->name] = $propertyPhp;
6✔
112
        }
113

114
        foreach ($clazz->getMethods() as $method) {
6✔
115
            $methodNameTmp = $method->getName();
6✔
116

117
            $this->methods[$methodNameTmp] = (new PHPMethod($this->parserContainer))->readObjectFromReflection($method);
6✔
118

119
            if (!$this->methods[$methodNameTmp]->file) {
6✔
120
                $this->methods[$methodNameTmp]->file = $this->file;
×
121
            }
122
        }
123

124
        foreach ($clazz->getReflectionConstants() as $constant) {
6✔
125
            $constantNameTmp = $constant->getName();
×
126

127
            $this->constants[$constantNameTmp] = (new PHPConst($this->parserContainer))->readObjectFromReflection($constant);
×
128

129
            if (!$this->constants[$constantNameTmp]->file) {
×
130
                $this->constants[$constantNameTmp]->file = $this->file;
×
131
            }
132
        }
133

134
        return $this;
6✔
135
    }
136

137
    /**
138
     * @param string[] $access
139
     * @param bool     $skipMethodsWithLeadingUnderscore
140
     *
141
     * @return array
142
     *
143
     * @psalm-return array<string, array{type: null|string, typeFromPhpDocMaybeWithComment: null|string, typeFromPhpDoc: null|string, typeFromPhpDocSimple: null|string, typeFromPhpDocExtended: null|string, typeFromDefaultValue: null|string}>
144
     */
145
    public function getPropertiesInfo(
146
        array $access = ['public', 'protected', 'private'],
147
        bool $skipMethodsWithLeadingUnderscore = false
148
    ): array {
149
        // init
150
        $allInfo = [];
3✔
151

152
        foreach ($this->properties as $property) {
3✔
153
            if (!\in_array($property->access, $access, true)) {
3✔
154
                continue;
×
155
            }
156

157
            if ($skipMethodsWithLeadingUnderscore && \strpos($property->name, '_') === 0) {
3✔
158
                continue;
×
159
            }
160

161
            $types = [];
3✔
162
            $types['type'] = $property->type;
3✔
163
            $types['typeFromPhpDocMaybeWithComment'] = $property->typeFromPhpDocMaybeWithComment;
3✔
164
            $types['typeFromPhpDoc'] = $property->typeFromPhpDoc;
3✔
165
            $types['typeFromPhpDocSimple'] = $property->typeFromPhpDocSimple;
3✔
166
            $types['typeFromPhpDocExtended'] = $property->typeFromPhpDocExtended;
3✔
167
            $types['typeFromDefaultValue'] = $property->typeFromDefaultValue;
3✔
168

169
            $allInfo[$property->name] = $types;
3✔
170
        }
171

172
        return $allInfo;
3✔
173
    }
174

175
    /**
176
     * @param string[] $access
177
     * @param bool     $skipDeprecatedMethods
178
     * @param bool     $skipMethodsWithLeadingUnderscore
179
     *
180
     * @return array<mixed>
181
     *
182
     * @psalm-return array<string, array{
183
     *     fullDescription: string,
184
     *     line: null|int,
185
     *     file: null|string,
186
     *     error: string,
187
     *     is_deprecated: bool,
188
     *     is_static: null|bool,
189
     *     is_meta: bool,
190
     *     is_internal: bool,
191
     *     is_removed: bool,
192
     *     paramsTypes: array<string,
193
     *         array{
194
     *              type?: null|string,
195
     *              typeFromPhpDoc?: null|string,
196
     *              typeFromPhpDocExtended?: null|string,
197
     *              typeFromPhpDocSimple?: null|string,
198
     *              typeFromPhpDocMaybeWithComment?: null|string,
199
     *              typeFromDefaultValue?: null|string
200
     *         }
201
     *     >,
202
     *     returnTypes: array{
203
     *         type: null|string,
204
     *         typeFromPhpDoc: null|string,
205
     *         typeFromPhpDocExtended: null|string,
206
     *         typeFromPhpDocSimple: null|string,
207
     *         typeFromPhpDocMaybeWithComment: null|string
208
     *     },
209
     *     paramsPhpDocRaw: array<string, null|string>,
210
     *     returnPhpDocRaw: null|string
211
     *  }>
212
     */
213
    public function getMethodsInfo(
214
        array $access = ['public', 'protected', 'private'],
215
        bool $skipDeprecatedMethods = false,
216
        bool $skipMethodsWithLeadingUnderscore = false
217
    ): array {
218
        // init
219
        $allInfo = [];
3✔
220

221
        foreach ($this->methods as $method) {
3✔
222
            if (!\in_array($method->access, $access, true)) {
3✔
223
                continue;
×
224
            }
225

226
            if ($skipDeprecatedMethods && $method->hasDeprecatedTag) {
3✔
227
                continue;
×
228
            }
229

230
            if ($skipMethodsWithLeadingUnderscore && \strpos($method->name, '_') === 0) {
3✔
231
                continue;
×
232
            }
233

234
            $paramsTypes = [];
3✔
235
            foreach ($method->parameters as $tagParam) {
3✔
236
                $paramsTypes[$tagParam->name]['type'] = $tagParam->type;
×
237
                $paramsTypes[$tagParam->name]['typeFromPhpDocMaybeWithComment'] = $tagParam->typeFromPhpDocMaybeWithComment;
×
238
                $paramsTypes[$tagParam->name]['typeFromPhpDoc'] = $tagParam->typeFromPhpDoc;
×
239
                $paramsTypes[$tagParam->name]['typeFromPhpDocSimple'] = $tagParam->typeFromPhpDocSimple;
×
240
                $paramsTypes[$tagParam->name]['typeFromPhpDocExtended'] = $tagParam->typeFromPhpDocExtended;
×
241
                $paramsTypes[$tagParam->name]['typeFromDefaultValue'] = $tagParam->typeFromDefaultValue;
×
242
            }
243

244
            $returnTypes = [];
3✔
245
            $returnTypes['type'] = $method->returnType;
3✔
246
            $returnTypes['typeFromPhpDocMaybeWithComment'] = $method->returnTypeFromPhpDocMaybeWithComment;
3✔
247
            $returnTypes['typeFromPhpDoc'] = $method->returnTypeFromPhpDoc;
3✔
248
            $returnTypes['typeFromPhpDocSimple'] = $method->returnTypeFromPhpDocSimple;
3✔
249
            $returnTypes['typeFromPhpDocExtended'] = $method->returnTypeFromPhpDocExtended;
3✔
250

251
            $paramsPhpDocRaw = [];
3✔
252
            foreach ($method->parameters as $tagParam) {
3✔
253
                $paramsPhpDocRaw[$tagParam->name] = $tagParam->phpDocRaw;
×
254
            }
255

256
            $infoTmp = [];
3✔
257
            $infoTmp['fullDescription'] = \trim($method->summary . "\n\n" . $method->description);
3✔
258
            $infoTmp['paramsTypes'] = $paramsTypes;
3✔
259
            $infoTmp['returnTypes'] = $returnTypes;
3✔
260
            $infoTmp['paramsPhpDocRaw'] = $paramsPhpDocRaw;
3✔
261
            $infoTmp['returnPhpDocRaw'] = $method->returnPhpDocRaw;
3✔
262
            $infoTmp['line'] = $method->line ?? $this->line;
3✔
263
            $infoTmp['file'] = $method->file ?? $this->file;
3✔
264
            $infoTmp['error'] = \implode("\n", $method->parseError);
3✔
265
            foreach ($method->parameters as $parameter) {
3✔
266
                $infoTmp['error'] .= ($infoTmp['error'] ? "\n" : '') . \implode("\n", $parameter->parseError);
×
267
            }
268
            $infoTmp['is_deprecated'] = $method->hasDeprecatedTag;
3✔
269
            $infoTmp['is_static'] = $method->is_static;
3✔
270
            $infoTmp['is_meta'] = $method->hasMetaTag;
3✔
271
            $infoTmp['is_internal'] = $method->hasInternalTag;
3✔
272
            $infoTmp['is_removed'] = $method->hasRemovedTag;
3✔
273

274
            $allInfo[$method->name] = $infoTmp;
3✔
275
        }
276

277
        \asort($allInfo);
3✔
278

279
        return $allInfo;
3✔
280
    }
281

282
    /**
283
     * @param Doc|string $docComment
284
     */
285
    private function readPhpDocProperties($doc): void
286
    {
287
        if ($doc instanceof Doc) {
6✔
288
            $docComment = $doc->getText();
6✔
289
        } else {
290
            $docComment = $doc;
×
291
        }
292
        if ($docComment === '') {
6✔
293
            return;
×
294
        }
295

296
        try {
297
            $phpDoc = Utils::createDocBlockInstance()->create($docComment);
6✔
298

299
            $parsedPropertyTags = $phpDoc->getTagsByName('property')
6✔
300
                               + $phpDoc->getTagsByName('property-read')
6✔
301
                               + $phpDoc->getTagsByName('property-write');
6✔
302

303
            if (!empty($parsedPropertyTags)) {
6✔
304
                foreach ($parsedPropertyTags as $parsedPropertyTag) {
6✔
305
                    if (
306
                        $parsedPropertyTag instanceof \phpDocumentor\Reflection\DocBlock\Tags\PropertyRead
×
307
                        ||
308
                        $parsedPropertyTag instanceof \phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite
×
309
                        ||
310
                        $parsedPropertyTag instanceof \phpDocumentor\Reflection\DocBlock\Tags\Property
×
311
                    ) {
312
                        $propertyPhp = new PHPProperty($this->parserContainer);
×
313

314
                        $nameTmp = $parsedPropertyTag->getVariableName();
×
315
                        if (!$nameTmp) {
×
316
                            continue;
×
317
                        }
318

319
                        $propertyPhp->name = $nameTmp;
×
320

321
                        $propertyPhp->access = 'public';
×
322

323
                        $type = $parsedPropertyTag->getType();
×
324

325
                        $propertyPhp->typeFromPhpDoc = Utils::normalizePhpType($type . '');
×
326

327
                        $typeFromPhpDocMaybeWithCommentTmp = \trim((string) $parsedPropertyTag);
×
328
                        if (
329
                            $typeFromPhpDocMaybeWithCommentTmp
×
330
                            &&
331
                            \strpos($typeFromPhpDocMaybeWithCommentTmp, '$') !== 0
×
332
                        ) {
333
                            $propertyPhp->typeFromPhpDocMaybeWithComment = $typeFromPhpDocMaybeWithCommentTmp;
×
334
                        }
335

336
                        $typeTmp = Utils::parseDocTypeObject($type);
×
337
                        if ($typeTmp !== '') {
×
338
                            $propertyPhp->typeFromPhpDocSimple = $typeTmp;
×
339
                        }
340

341
                        if ($propertyPhp->typeFromPhpDoc) {
×
342
                            $propertyPhp->typeFromPhpDocExtended = Utils::modernPhpdoc($propertyPhp->typeFromPhpDoc);
×
343
                        }
344

345
                        $this->properties[$propertyPhp->name] = $propertyPhp;
×
346
                    }
347
                }
348
            }
349
        } catch (\Exception $e) {
×
350
            $tmpErrorMessage = ($this->name ?: '?') . ':' . ($this->line ?? '?') . ' | ' . \print_r($e->getMessage(), true);
×
351
            $this->parseError[\md5($tmpErrorMessage)] = $tmpErrorMessage;
×
352
        }
353
    }
354
}
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