TypeResolver::extractTypeFromCollectionType()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace Tonic\Component\Reflection;
4
5
use Doctrine\Common\Annotations\PhpParser;
6
use phpDocumentor\Reflection\DocBlock;
7
use phpDocumentor\Reflection\DocBlock\Tag\ReturnTag;
8
use phpDocumentor\Reflection\DocBlock\Tag\VarTag;
9
10
/**
11
 * Resolves types by comments.
12
 */
13
class TypeResolver
14
{
15
    /**
16
     * @var PhpParser
17
     */
18
    private $phpParser;
19
20
    /**
21
     * @param PhpParser $phpParser
22
     */
23
    public function __construct(PhpParser $phpParser)
24
    {
25
        $this->phpParser = $phpParser;
26
    }
27
28
    /**
29
     * @param \ReflectionProperty $reflectionProperty
30
     *
31
     * @return null|string
32
     */
33
    public function resolvePropertyType(\ReflectionProperty $reflectionProperty)
34
    {
35
        return $this->resolveElementType($reflectionProperty, 'var');
36
    }
37
38
    /**
39
     * @param \ReflectionFunctionAbstract $reflectionFunction
40
     *
41
     * @return string
42
     */
43
    public function resolveFunctionReturnType(\ReflectionFunctionAbstract $reflectionFunction)
44
    {
45
        $this->resolveElementType($reflectionFunction, 'return');
46
    }
47
48
    /**
49
     * @param \Reflector $reflector
50
     * @param string $tagName
51
     *
52
     * @return string|null
53
     */
54
    public function resolveElementType(\Reflector $reflector, $tagName)
55
    {
56
        $docBlock = new DocBlock($reflector);
57
        $returnTags = $docBlock->getTagsByName($tagName);
58
59
        /** @var ReturnTag $returnTag */
60
        $returnTag = reset($returnTags);
61
62
        $type = $returnTag->getType();
63
64
        $isCollection = false;
65
        if ($extractedType = $this->extractTypeFromCollectionType($type)) {
66
            $isCollection = true;
67
            $type = $extractedType;
68
        }
69
70
        if (static::isTypeObject($type) && ($reflector instanceof \ReflectionMethod || $reflector instanceof \ReflectionProperty)) {
71
            $type = $this->resolveClassName($type, $reflector->getDeclaringClass());
72
        }
73
74
        return $type.($isCollection ? '[]' : '');
75
    }
76
77
    /**
78
     * @param string $type
79
     *
80
     * @return bool
81
     */
82
    protected function isTypeObject($type)
83
    {
84
        switch (strtolower($type)) {
85
            case 'int':
86
            case 'integer':
87
            case 'string':
88
            case 'array':
89
            case 'float':
90
            case 'double':
91
            case 'real':
92
            case 'bool':
93
            case 'boolean':
94
            case 'resource':
95
            case 'mixed':
96
            case 'null':
97
            case 'long':
98
            case 'numeric':
99
            case 'callable':
100
                return false;
101
            default:
102
                return true;
103
        }
104
    }
105
106
    private function resolveClassName($type, \ReflectionClass $usingClass)
107
    {
108
        if (strpos($type, '\\') === 0 && class_exists($type)) {
109
            return $type;
110
        }
111
112
        if (strpos($type, '\\') === 0) {
113
            $type = substr($type, 1);
114
        }
115
116
        $aliases = $this->phpParser->parseClass($usingClass);
117
        $alias = strtolower($type);
118
119
        if (!isset($aliases[$alias])) {
120
            return $usingClass->getNamespaceName().'\\'.$type;
121
        }
122
123
        return $aliases[$alias];
124
    }
125
126
    /**
127
     * @param string $type
128
     *
129
     * @return string|null
130
     */
131
    public function extractTypeFromCollectionType($type)
132
    {
133
        if (($pos = strpos($type, '[')) !== false) {
134
            $type = substr($type, 0, $pos);
135
136
            return $type;
137
        }
138
139
        return null;
140
    }
141
}
142