Completed
Push — master ( 4de33b...358f66 )
by Jamie
01:33
created

TypeHintReader::getParameter()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 3
nop 2
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Thr;
4
5
/**
6
 * Class TypeHintReader
7
 * @package Thr
8
 */
9
class TypeHintReader implements TypeReader
10
{
11
    private $class;
12
13
    /**
14
     * TypeHintReader constructor.
15
     * @param \ReflectionClass $class
16
     */
17
    public function __construct(\ReflectionClass $class)
18
    {
19
        $this->class = $class;
20
    }
21
22
    /**
23
     * {@inheritdoc}
24
     */
25
    public function getReflectionType(string $propertyName): \ReflectionType
26
    {
27
        $reflectionType = $this->getReflectionParameter($propertyName)
28
            ->getType();
29
        if ($reflectionType === null) {
30
            throw TypeHintReaderException::withoutTypeHint($propertyName);
31
        }
32
33
        return $reflectionType;
34
    }
35
36
    private function getReflectionParameter(
37
        string $propertyName
38
    ): \ReflectionParameter {
39
        return $this->getReflectionPropertyBySetter($propertyName)
40
            ?? $this->getReflectionPropertyByConstruct($propertyName);
41
    }
42
43
    private function getReflectionPropertyBySetter(
44
        string $propertyName
45
    ): ?\ReflectionParameter {
46
        $nameSetter = 'set'.ucfirst($propertyName);
47
        if ($this->class->hasMethod($nameSetter)) {
48
            $methodSetter = $this->class->getMethod($nameSetter);
49
            return $methodSetter->getParameters()[0];
50
        }
51
52
        return null;
53
    }
54
55
    private function getReflectionPropertyByConstruct(
56
        string $propertyName
57
    ): \ReflectionParameter {
58
        $constructor = $this->class->getConstructor();
59
        $parameter = $this->getParameter($propertyName, $constructor);
60
61
        if ($parameter instanceof \ReflectionParameter) {
62
            return $parameter;
63
        }
64
65
        throw TypeHintReaderException::invalidPropertyName($propertyName);
66
    }
67
68
    private function getParameter(
69
        string $propertyName,
70
        \ReflectionMethod $constructor
71
    ): ?\ReflectionParameter {
72
        foreach ($constructor->getParameters() as $parameter) {
73
            if ($parameter->getName() === $propertyName) {
74
                return $parameter;
75
            }
76
        }
77
78
        return null;
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84
    public function getTypeName(string $propertyName): string
85
    {
86
        return $this->getReflectionType($propertyName)->getName();
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function typeAllowNull(string $propertyName): bool
93
    {
94
        return $this->getReflectionType($propertyName)->allowsNull();
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100
    public function typeIsBuiltin(string $propertyName): bool
101
    {
102
        return $this->getReflectionType($propertyName)->isBuiltin();
103
    }
104
105
    /**
106
     * @param string $class
107
     * @return TypeHintReader
108
     * @throws TypeHintReaderException
109
     * @throws \ReflectionException
110
     */
111
    public static function byClassName(string $class): self
112
    {
113
        if (!class_exists($class)) {
114
            throw TypeHintReaderException::notExistsClass($class);
115
        }
116
117
        return new self(new \ReflectionClass($class));
118
    }
119
}
120