• 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

60.83
/src/voku/SimplePhpParser/Model/PHPFunction.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace voku\SimplePhpParser\Model;
6

7
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
8
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
9
use PhpParser\Comment\Doc;
10
use PhpParser\Node\Stmt\Function_;
11
use ReflectionFunction;
12
use voku\SimplePhpParser\Parsers\Helper\DocFactoryProvider;
13
use voku\SimplePhpParser\Parsers\Helper\Utils;
14

15
class PHPFunction extends BasePHPElement
16
{
17
    use PHPDocElement;
18

19
    /**
20
     * @var PHPParameter[]
21
     */
22
    public $parameters = [];
23

24
    /**
25
     * @var string|null
26
     */
27
    public $returnPhpDocRaw;
28

29
    /**
30
     * @var string|null
31
     */
32
    public $returnType;
33

34
    /**
35
     * @var string|null
36
     */
37
    public $returnTypeFromPhpDoc;
38

39
    /**
40
     * @var string|null
41
     */
42
    public $returnTypeFromPhpDocSimple;
43

44
    /**
45
     * @var string|null
46
     */
47
    public $returnTypeFromPhpDocExtended;
48

49
    /**
50
     * @var string|null
51
     */
52
    public $returnTypeFromPhpDocMaybeWithComment;
53

54
    /**
55
     * @var string
56
     */
57
    public $summary = '';
58

59
    /**
60
     * @var string
61
     */
62
    public $description = '';
63

64
    /**
65
     * @param Function_ $node
66
     * @param string|null      $dummy
67
     *
68
     * @return $this
69
     */
70
    public function readObjectFromPhpNode($node, $dummy = null): self
71
    {
72
        $this->prepareNode($node);
24✔
73

74
        $this->name = static::getFQN($node);
24✔
75

76
        /** @noinspection NotOptimalIfConditionsInspection */
77
        if (\function_exists($this->name)) {
24✔
78
            $reflectionFunction = Utils::createFunctionReflectionInstance($this->name);
15✔
79
            $this->readObjectFromReflection($reflectionFunction);
15✔
80
        }
81

82
        if ($node->returnType) {
24✔
83
            if (!$this->returnType) {
×
84
                if (\method_exists($node->returnType, 'toString')) {
×
85
                    $this->returnType = $node->returnType->toString();
×
86
                } elseif (\property_exists($node->returnType, 'name')) {
×
87
                    /** @psalm-suppress UndefinedPropertyFetch - FP? */
88
                    $this->returnType = $node->returnType->name;
×
89
                }
90
            }
91

92
            if ($node->returnType instanceof \PhpParser\Node\NullableType) {
×
93
                if ($this->returnType && $this->returnType !== 'null' && \strpos($this->returnType, 'null|') !== 0) {
×
94
                    $this->returnType = 'null|' . $this->returnType;
×
95
                } elseif (!$this->returnType) {
×
96
                    $this->returnType = 'null|mixed';
×
97
                }
98
            }
99
        }
100

101
        $docComment = $node->getDocComment();
24✔
102
        if ($docComment) {
24✔
103
            try {
104
                $phpDoc = Utils::createDocBlockInstance()->create($docComment->getText());
21✔
105
                $this->summary = $phpDoc->getSummary();
21✔
106
                $this->description = (string) $phpDoc->getDescription();
21✔
107
            } catch (\Exception $e) {
×
108
                $tmpErrorMessage = \sprintf(
×
109
                    '%s:%s | %s',
×
110
                    $this->name,
×
111
                    $this->line ?? '?',
×
112
                    \print_r($e->getMessage(), true)
×
113
                );
×
114
                $this->parseError[\md5($tmpErrorMessage)] = $tmpErrorMessage;
×
115
            }
116
        }
117

118
        foreach ($node->getParams() as $parameter) {
24✔
119
            $parameterVar = $parameter->var;
24✔
120
            if ($parameterVar instanceof \PhpParser\Node\Expr\Error) {
24✔
121
                $this->parseError[] = \sprintf(
×
122
                    '%s:%s | maybe at this position an expression is required',
×
123
                    $this->line ?? '?',
×
124
                    $this->pos ?? ''
×
125
                );
×
126

127
                return $this;
×
128
            }
129

130
            $paramNameTmp = $parameterVar->name;
24✔
131
            \assert(\is_string($paramNameTmp));
132

133
            if (isset($this->parameters[$paramNameTmp])) {
24✔
134
                $this->parameters[$paramNameTmp] = $this->parameters[$paramNameTmp]->readObjectFromPhpNode($parameter, $node);
15✔
135
            } else {
136
                $this->parameters[$paramNameTmp] = (new PHPParameter($this->parserContainer))->readObjectFromPhpNode($parameter, $node);
11✔
137
            }
138
        }
139

140
        $this->collectTags($node);
24✔
141

142
        $docComment = $node->getDocComment();
24✔
143
        if ($docComment) {
24✔
144
            $this->readPhpDoc($docComment);
21✔
145
        }
146

147
        return $this;
24✔
148
    }
149

150
    /**
151
     * @param ReflectionFunction $function
152
     *
153
     * @return $this
154
     */
155
    public function readObjectFromReflection($function): self
156
    {
157
        $this->name = $function->getName();
15✔
158

159
        if (!$this->line) {
15✔
160
            $lineTmp = $function->getStartLine();
×
161
            if ($lineTmp !== false) {
×
162
                $this->line = $lineTmp;
×
163
            }
164
        }
165

166
        $file = $function->getFileName();
15✔
167
        if ($file) {
15✔
168
            $this->file = $file;
12✔
169
        }
170

171
        $returnType = $function->getReturnType();
15✔
172
        if ($returnType !== null) {
15✔
173
            if (\method_exists($returnType, 'getName')) {
×
174
                $this->returnType = $returnType->getName();
×
175
            } else {
176
                $this->returnType = $returnType . '';
×
177
            }
178

179
            if ($returnType->allowsNull()) {
×
180
                if ($this->returnType && $this->returnType !== 'null' && \strpos($this->returnType, 'null|') !== 0) {
×
181
                    $this->returnType = 'null|' . $this->returnType;
×
182
                } elseif (!$this->returnType) {
×
183
                    $this->returnType = 'null|mixed';
×
184
                }
185
            }
186
        }
187

188
        $docComment = $function->getDocComment();
15✔
189
        if ($docComment) {
15✔
190
            $this->readPhpDoc($docComment);
12✔
191
        }
192

193
        if (!$this->returnTypeFromPhpDoc) {
15✔
194
            try {
195
                $phpDoc = DocFactoryProvider::getDocFactory()->create((string)$function->getDocComment());
6✔
196
                $returnTypeTmp = $phpDoc->getTagsByName('return');
×
197
                if (
198
                    \count($returnTypeTmp) === 1
×
199
                    &&
200
                    $returnTypeTmp[0] instanceof \phpDocumentor\Reflection\DocBlock\Tags\Return_
×
201
                ) {
202
                    $this->returnTypeFromPhpDoc = Utils::parseDocTypeObject($returnTypeTmp[0]->getType());
×
203
                }
204
            } catch (\Exception $e) {
6✔
205
                // ignore
206
            }
207
        }
208

209
        foreach ($function->getParameters() as $parameter) {
15✔
210
            $param = (new PHPParameter($this->parserContainer))->readObjectFromReflection($parameter);
15✔
211
            $this->parameters[$param->name] = $param;
15✔
212
        }
213

214
        $docComment = $function->getDocComment();
15✔
215
        if ($docComment) {
15✔
216
            $this->readPhpDoc($docComment);
12✔
217
        }
218

219
        return $this;
15✔
220
    }
221

222
    /**
223
     * @return string|null
224
     */
225
    public function getReturnType(): ?string
226
    {
227
        if ($this->returnTypeFromPhpDocExtended) {
×
228
            return $this->returnTypeFromPhpDocExtended;
×
229
        }
230

231
        if ($this->returnType) {
×
232
            return $this->returnType;
×
233
        }
234

235
        if ($this->returnTypeFromPhpDocSimple) {
×
236
            return $this->returnTypeFromPhpDocSimple;
×
237
        }
238

239
        return null;
×
240
    }
241

242
    /**
243
     * @param Doc|string $doc
244
     */
245
    protected function readPhpDoc($doc): void
246
    {
247
        if ($doc instanceof Doc) {
44✔
248
            $docComment = $doc->getText();
41✔
249
        } else {
250
            $docComment = $doc;
35✔
251
        }
252
        if ($docComment === '') {
44✔
253
            return;
×
254
        }
255

256
        try {
257
            $phpDoc = Utils::createDocBlockInstance()->create($docComment);
44✔
258

259
            $parsedReturnTag = $phpDoc->getTagsByName('return');
44✔
260

261
            if (!empty($parsedReturnTag)) {
44✔
262
                /** @var Return_ $parsedReturnTagReturn */
263
                $parsedReturnTagReturn = $parsedReturnTag[0];
41✔
264

265
                if ($parsedReturnTagReturn instanceof Return_) {
41✔
266
                    $this->returnTypeFromPhpDocMaybeWithComment = \trim((string) $parsedReturnTagReturn);
41✔
267

268
                    $type = $parsedReturnTagReturn->getType();
41✔
269

270
                    $this->returnTypeFromPhpDoc = Utils::normalizePhpType(\ltrim((string) $type, '\\'));
41✔
271

272
                    $typeTmp = Utils::parseDocTypeObject($type);
41✔
273
                    if ($typeTmp !== '') {
41✔
274
                        $this->returnTypeFromPhpDocSimple = $typeTmp;
41✔
275
                    }
276
                }
277

278
                $this->returnPhpDocRaw = (string) $parsedReturnTagReturn;
41✔
279
                $this->returnTypeFromPhpDocExtended = Utils::modernPhpdoc((string) $parsedReturnTagReturn);
41✔
280
            }
281

282
            $parsedReturnTag = $phpDoc->getTagsByName('psalm-return')
44✔
283
                               + $phpDoc->getTagsByName('phpstan-return');
44✔
284

285
            if (!empty($parsedReturnTag) && $parsedReturnTag[0] instanceof Generic) {
44✔
286
                $parsedReturnTagReturn = (string) $parsedReturnTag[0];
35✔
287

288
                $this->returnTypeFromPhpDocExtended = Utils::modernPhpdoc($parsedReturnTagReturn);
44✔
289
            }
290
        } catch (\Exception $e) {
11✔
291
            $tmpErrorMessage = \sprintf(
11✔
292
                '%s:%s | %s',
11✔
293
                $this->name,
11✔
294
                $this->line ?? '?',
11✔
295
                \print_r($e->getMessage(), true)
11✔
296
            );
11✔
297
            $this->parseError[\md5($tmpErrorMessage)] = $tmpErrorMessage;
11✔
298
        }
299
    }
300
}
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

© 2025 Coveralls, Inc