Metadata::forReflectionMethod()   A
last analyzed

Complexity

Conditions 5
Paths 12

Size

Total Lines 32
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 3
Metric Value
cc 5
eloc 22
c 4
b 0
f 3
nc 12
nop 1
dl 0
loc 32
rs 9.2568
1
<?php
2
3
/*
4
 * This file is part of the PHINT package.
5
 *
6
 * (c) Jitendra Adhikari <[email protected]>
7
 *     <https://github.com/adhocore>
8
 *
9
 * Licensed under MIT license.
10
 */
11
12
namespace Ahc\Phint\Util;
13
14
use CrazyFactory\DocBlocks\DocBlock;
15
16
class Metadata
17
{
18
    public function forClass(string $classFqcn): array
19
    {
20
        return $this->forReflectionClass(new \ReflectionClass($classFqcn));
21
    }
22
23
    public function forReflectionClass(\ReflectionClass $class): array
24
    {
25
        $name  = $class->name;
26
        $texts = (new DocBlock($class))->texts();
27
        $title = \array_shift($texts);
28
29
        $metadata = [
30
            'namespace'   => \preg_replace('!\W\w+$!', '', $name),
31
            'classFqcn'   => $name,
32
            'classPath'   => $class->getFileName(),
33
            'name'        => $class->getShortName(),
34
            'className'   => $class->getShortName(),
35
            'isTrait'     => $class->isTrait(),
36
            'isAbstract'  => $class->isAbstract(),
37
            'isInterface' => $class->isInterface(),
38
            'newable'     => $class->isInstantiable(),
39
            'title'       => $title,
40
            'texts'       => $texts,
41
            'methods'     => [],
42
        ];
43
44
        foreach ($class->getMethods() as $method) {
45
            if ($method->class !== $name) {
46
                continue;
47
            }
48
49
            $metadata['methods'][$method->name] = $this->forReflectionMethod($method);
50
        }
51
52
        return $metadata;
53
    }
54
55
    public function forMethod(string $classFqcn, string $method): array
56
    {
57
        $reflMethod = (new \ReflectionClass($classFqcn))->getMethod($method);
58
59
        return $this->forReflectionMethod($reflMethod);
60
    }
61
62
    public function forReflectionMethod(\ReflectionMethod $method): array
63
    {
64
        $parser = new DocBlock($method);
65
        $texts  = $parser->texts();
66
        $title  = \array_shift($texts);
67
        $throws = $parser->first('throws');
68
69
        $metadata = [
70
            'name'       => $method->name,
71
            'inClass'    => $method->getDeclaringClass()->name,
72
            'isStatic'   => $method->isStatic(),
73
            'isFinal'    => $method->isFinal(),
74
            'isPublic'   => $method->isPublic(),
75
            'isAbstract' => $method->isAbstract(),
76
            'maybeMagic' => \substr($method->name, 0, 2) === '__',
77
            'throws'     => $throws ? \explode(' ', \trim($throws->getValue()), 2) : [],
0 ignored issues
show
Bug introduced by
It seems like $throws->getValue() can also be of type null; however, parameter $string of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

77
            'throws'     => $throws ? \explode(' ', \trim(/** @scrutinizer ignore-type */ $throws->getValue()), 2) : [],
Loading history...
78
            'title'      => $title,
79
            'texts'      => $texts,
80
        ];
81
82
        $params = [];
83
        foreach ($parser->find('param') as $param) {
84
            if (\preg_match('/(.*)\$(\w+)(.*)/', $param->getValue(), $match)) {
85
                $params[$match[2]] = [\trim($match[1]), \trim($match[3])];
86
            }
87
        }
88
89
        if (null !== $return = $parser->first('return')) {
90
            $return = \explode(' ', \trim($return->getValue()), 2);
91
        }
92
93
        return $metadata + $this->getMethodParameters($method, $params, $return ?? []);
94
    }
95
96
    protected function getMethodParameters(\ReflectionMethod $method, array $docParams, array $return)
97
    {
98
        $params = [];
99
        $parser = new DocBlock($method);
0 ignored issues
show
Unused Code introduced by
The assignment to $parser is dead and can be removed.
Loading history...
100
101
        foreach ($method->getParameters() as $param) {
102
            $name = $param->name;
103
            if (!$param->hasType()) {
104
                $params[] = [\trim(($docParams[$name][0] ?? '') . " \$$name"), $docParams[$name][1] ?? ''];
105
106
                continue;
107
            }
108
109
            $params[] = [$this->getRealType($param) . " \$$name", $docParams[$name][1] ?? ''];
110
        }
111
112
        if ($returnType = $method->getReturnType()) {
113
            $return = [$this->getRealType($returnType), $return[1] ?? ''];
114
        }
115
116
        return \compact('params', 'return');
117
    }
118
119
    protected function getRealType($param): string
120
    {
121
        $type = \method_exists($param, 'getType')
122
            ? $param->getType()
123
            : (string) $param;
124
125
        if (\preg_match('/void|null/', $type)) {
126
            return $type;
127
        }
128
129
        return $type . ($param->allowsNull() ? '|null' : '');
130
    }
131
}
132