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

voku / Simple-PHP-Code-Parser / 5709606856

pending completion
5709606856

push

github

voku
[+]: ci: run test with PHP 8.2

1305 of 1592 relevant lines covered (81.97%)

7.61 hits per line

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

78.95
/src/voku/SimplePhpParser/Model/PHPProperty.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\Property;
9
use ReflectionProperty;
10
use voku\SimplePhpParser\Parsers\Helper\Utils;
11

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

19
    public ?string $phpDocRaw = null;
20

21
    public ?string $type = null;
22

23
    public ?string $typeFromDefaultValue = null;
24

25
    public ?string $typeFromPhpDoc = null;
26

27
    public ?string $typeFromPhpDocSimple = null;
28

29
    public ?string $typeFromPhpDocExtended = null;
30

31
    public ?string $typeFromPhpDocMaybeWithComment = null;
32

33
    /**
34
     * @phpstan-var ''|'private'|'protected'|'public'
35
     */
36
    public string $access = '';
37

38
    public ?bool $is_static = null;
39

40
    public ?bool $is_readonly = null;
41

42
    public ?bool $is_inheritdoc = null;
43

44
    /**
45
     * @param Property    $node
46
     * @param string|null $classStr
47
     *
48
     * @phpstan-param class-string|null $classStr
49
     *
50
     * @return $this
51
     */
52
    public function readObjectFromPhpNode($node, $classStr = null): self
53
    {
54
        $this->name = $this->getConstantFQN($node, $node->props[0]->name->name);
11✔
55

56
        $this->is_static = $node->isStatic();
11✔
57

58
        if (method_exists($node, 'isReadonly')) {
11✔
59
            $this->is_readonly = $node->isReadonly();
11✔
60
        }
61

62
        $this->prepareNode($node);
11✔
63

64
        $docComment = $node->getDocComment();
11✔
65
        if ($docComment) {
11✔
66
            $docCommentText = $docComment->getText();
10✔
67

68
            if (\stripos($docCommentText, '@inheritdoc') !== false) {
10✔
69
                $this->is_inheritdoc = true;
×
70
            }
71

72
            $this->readPhpDoc($docComment);
10✔
73
        }
74

75
        if ($node->type !== null) {
11✔
76
            if (!$this->type) {
3✔
77
                if (\method_exists($node->type, 'getParts')) {
×
78
                    $parts = $node->type->getParts();
×
79
                    if (!empty($parts)) {
×
80
                        $this->type = '\\' . \implode('\\', $parts);
×
81
                    }
82
                } elseif (\property_exists($node->type, 'name') && $node->type->name) {
×
83
                    $this->type = $node->type->name;
×
84
                }
85
            }
86

87
            if ($node->type instanceof \PhpParser\Node\NullableType) {
3✔
88
                if ($this->type && $this->type !== 'null' && \strpos($this->type, 'null|') !== 0) {
1✔
89
                    $this->type = 'null|' . $this->type;
×
90
                } elseif (!$this->type) {
1✔
91
                    $this->type = 'null|mixed';
×
92
                }
93
            }
94
        }
95

96
        if ($node->props[0]->default !== null) {
11✔
97
            $defaultValue = Utils::getPhpParserValueFromNode($node->props[0]->default, $classStr);
7✔
98
            if ($defaultValue !== Utils::GET_PHP_PARSER_VALUE_FROM_NODE_HELPER) {
7✔
99
                $this->defaultValue = $defaultValue;
7✔
100

101
                $this->typeFromDefaultValue = Utils::normalizePhpType(\gettype($this->defaultValue));
7✔
102
            }
103
        }
104

105
        if ($node->isPrivate()) {
11✔
106
            $this->access = 'private';
×
107
        } elseif ($node->isProtected()) {
11✔
108
            $this->access = 'protected';
1✔
109
        } else {
110
            $this->access = 'public';
11✔
111
        }
112

113
        return $this;
11✔
114
    }
115

116
    /**
117
     * @param ReflectionProperty $property
118
     *
119
     * @return $this
120
     */
121
    public function readObjectFromReflection($property): self
122
    {
123
        $this->name = $property->getName();
14✔
124

125
        $file = $property->getDeclaringClass()->getFileName();
14✔
126
        if ($file) {
14✔
127
            $this->file = $file;
14✔
128
        }
129

130
        $this->is_static = $property->isStatic();
14✔
131

132
        if ($this->is_static) {
14✔
133
            try {
134
                if (\class_exists($property->getDeclaringClass()->getName(), true)) {
1✔
135
                    $this->defaultValue = $property->getValue();
1✔
136
                }
137
            } catch (\Exception $e) {
×
138
                // nothing
139
            }
140

141
            if ($this->defaultValue !== null) {
1✔
142
                $this->typeFromDefaultValue = Utils::normalizePhpType(\gettype($this->defaultValue));
1✔
143
            }
144
        }
145

146
        if (method_exists($property, 'isReadOnly')) {
14✔
147
            $this->is_readonly = $property->isReadOnly();
14✔
148
        }
149

150
        $docComment = $property->getDocComment();
14✔
151
        if ($docComment) {
14✔
152
            if (\stripos($docComment, '@inheritdoc') !== false) {
12✔
153
                $this->is_inheritdoc = true;
×
154
            }
155

156
            $this->readPhpDoc($docComment);
12✔
157
        }
158

159
        if (\method_exists($property, 'getType')) {
14✔
160
            $type = $property->getType();
14✔
161
            if ($type !== null) {
14✔
162
                if (\method_exists($type, 'getName')) {
4✔
163
                    $this->type = Utils::normalizePhpType($type->getName(), true);
4✔
164
                } else {
165
                    $this->type = Utils::normalizePhpType($type . '', true);
×
166
                }
167
                try {
168
                    if ($this->type && \class_exists($this->type, true)) {
4✔
169
                        $this->type = '\\' . \ltrim($this->type, '\\');
4✔
170
                    }
171
                } catch (\Exception $e) {
×
172
                    // nothing
173
                }
174

175
                if ($type->allowsNull()) {
4✔
176
                    if ($this->type && $this->type !== 'null' && \strpos($this->type, 'null|') !== 0) {
1✔
177
                        $this->type = 'null|' . $this->type;
1✔
178
                    } elseif (!$this->type) {
×
179
                        $this->type = 'null|mixed';
×
180
                    }
181
                }
182
            }
183
        }
184

185
        if ($property->isProtected()) {
14✔
186
            $access = 'protected';
4✔
187
        } elseif ($property->isPrivate()) {
13✔
188
            $access = 'private';
1✔
189
        } else {
190
            $access = 'public';
13✔
191
        }
192
        $this->access = $access;
14✔
193

194
        return $this;
14✔
195
    }
196

197
    /**
198
     * @return string|null
199
     */
200
    public function getType(): ?string
201
    {
202
        if ($this->typeFromPhpDocExtended) {
1✔
203
            return $this->typeFromPhpDocExtended;
1✔
204
        }
205

206
        if ($this->type) {
1✔
207
            return $this->type;
1✔
208
        }
209

210
        if ($this->typeFromPhpDocSimple) {
×
211
            return $this->typeFromPhpDocSimple;
×
212
        }
213

214
        return null;
×
215
    }
216

217
    /**
218
     * @param Doc|string $doc
219
     */
220
    private function readPhpDoc($doc): void
221
    {
222
        if ($doc instanceof Doc) {
12✔
223
            $docComment = $doc->getText();
10✔
224
        } else {
225
            $docComment = $doc;
12✔
226
        }
227
        if ($docComment === '') {
12✔
228
            return;
×
229
        }
230

231
        try {
232
            $phpDoc = Utils::createDocBlockInstance()->create($docComment);
12✔
233

234
            $parsedParamTags = $phpDoc->getTagsByName('var');
12✔
235

236
            if (!empty($parsedParamTags)) {
12✔
237
                foreach ($parsedParamTags as $parsedParamTag) {
12✔
238
                    if ($parsedParamTag instanceof \phpDocumentor\Reflection\DocBlock\Tags\Var_) {
12✔
239
                        $type = $parsedParamTag->getType();
12✔
240

241
                        $this->typeFromPhpDoc = Utils::normalizePhpType($type . '');
12✔
242

243
                        $typeFromPhpDocMaybeWithCommentTmp = \trim((string) $parsedParamTag);
12✔
244
                        if (
245
                            $typeFromPhpDocMaybeWithCommentTmp
12✔
246
                            &&
247
                            \strpos($typeFromPhpDocMaybeWithCommentTmp, '$') !== 0
12✔
248
                        ) {
249
                            $this->typeFromPhpDocMaybeWithComment = $typeFromPhpDocMaybeWithCommentTmp;
12✔
250
                        }
251

252
                        $typeTmp = Utils::parseDocTypeObject($type);
12✔
253
                        if ($typeTmp !== '') {
12✔
254
                            $this->typeFromPhpDocSimple = $typeTmp;
12✔
255
                        }
256
                    }
257

258
                    $this->phpDocRaw = (string) $parsedParamTag;
12✔
259
                    $this->typeFromPhpDocExtended = Utils::modernPhpdoc((string) $parsedParamTag);
12✔
260
                }
261
            }
262

263
            $parsedParamTags = $phpDoc->getTagsByName('psalm-var')
12✔
264
                               + $phpDoc->getTagsByName('phpstan-var');
12✔
265

266
            if (!empty($parsedParamTags)) {
12✔
267
                foreach ($parsedParamTags as $parsedParamTag) {
12✔
268
                    if (!$parsedParamTag instanceof \phpDocumentor\Reflection\DocBlock\Tags\Generic) {
6✔
269
                        continue;
×
270
                    }
271

272
                    $spitedData = Utils::splitTypeAndVariable($parsedParamTag);
6✔
273
                    $parsedParamTagStr = $spitedData['parsedParamTagStr'];
6✔
274

275
                    $this->typeFromPhpDocExtended = Utils::modernPhpdoc($parsedParamTagStr);
6✔
276
                }
277
            }
278
        } catch (\Exception $e) {
×
279
            $tmpErrorMessage = $this->name . ':' . ($this->line ?? '?') . ' | ' . \print_r($e->getMessage(), true);
×
280
            $this->parseError[\md5($tmpErrorMessage)] = $tmpErrorMessage;
×
281
        }
282
    }
283
}
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