Completed
Push — master ( 8507e2...2d694e )
by Lars
01:39
created

TypeCheckPhpDoc::throwException()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 3
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arrayy\TypeCheck;
6
7
/**
8
 * inspired by https://github.com/spatie/value-object
9
 *
10
 * @internal
11
 */
12
final class TypeCheckPhpDoc extends AbstractTypeCheck implements TypeCheckInterface
13
{
14
    /**
15
     * @var bool
16
     */
17
    private $hasTypeDeclaration = false;
18
19
    /**
20
     * @var string
21
     */
22
    private $property_name;
23
24
    /**
25
     * @param string $reflectionPropertyName
26
     */
27 2
    public function __construct($reflectionPropertyName)
28
    {
29 2
        $this->property_name = $reflectionPropertyName;
30 2
    }
31
32
    /**
33
     * @param \phpDocumentor\Reflection\DocBlock\Tags\Property $phpDocumentorReflectionProperty
34
     *
35
     * @return static
36
     */
37 2
    public static function fromPhpDocumentorProperty(\phpDocumentor\Reflection\DocBlock\Tags\Property $phpDocumentorReflectionProperty): self
38
    {
39 2
        $tmpProperty = $phpDocumentorReflectionProperty->getVariableName();
40 2
        $tmpObject = new \stdClass();
41 2
        $tmpObject->{$tmpProperty} = null;
42
43 2
        $tmpReflection = new self((new \ReflectionProperty($tmpObject, $tmpProperty))->getName());
44
45 2
        $type = $phpDocumentorReflectionProperty->getType();
46
47 2
        if ($type) {
48 2
            $tmpReflection->hasTypeDeclaration = true;
49
50 2
            $docTypes = self::parseDocTypeObject($type);
51 2
            if (\is_array($docTypes) === true) {
52 2
                foreach ($docTypes as $docType) {
53 2
                    $tmpReflection->types[] = $docType;
54
                }
55
            } else {
56 2
                $tmpReflection->types[] = $docTypes;
57
            }
58
59 2
            if (\in_array('null', $tmpReflection->types, true)) {
60 2
                $tmpReflection->isNullable = true;
61
            }
62
        }
63
64 2
        return $tmpReflection;
65
    }
66
67
    /**
68
     * @param \phpDocumentor\Reflection\Type $type
69
     *
70
     * @return string|string[]
71
     */
72 2
    public static function parseDocTypeObject($type)
73
    {
74 2
        if ($type instanceof \phpDocumentor\Reflection\Types\Object_) {
75 1
            $tmpObject = (string) $type->getFqsen();
76 1
            if ($tmpObject) {
77 1
                return $tmpObject;
78
            }
79
80
            return 'object';
81
        }
82
83 2
        if ($type instanceof \phpDocumentor\Reflection\Types\Compound) {
84 2
            $types = [];
85 2
            foreach ($type as $subType) {
86 2
                $types[] = self::parseDocTypeObject($subType);
87
            }
88
89 2
            return $types;
90
        }
91
92 2
        if ($type instanceof \phpDocumentor\Reflection\Types\Array_) {
93 1
            $valueTypeTmp = $type->getValueType() . '';
94 1
            if ($valueTypeTmp !== 'mixed') {
95 1
                return $valueTypeTmp . '[]';
96
            }
97
98
            return 'array';
99
        }
100
101 2
        if ($type instanceof \phpDocumentor\Reflection\Types\Null_) {
102 2
            return 'null';
103
        }
104
105 2
        if ($type instanceof \phpDocumentor\Reflection\Types\Mixed_) {
106
            return 'mixed';
107
        }
108
109 2
        if ($type instanceof \phpDocumentor\Reflection\Types\Scalar) {
110
            return 'string|int|float|bool';
111
        }
112
113 2
        if ($type instanceof \phpDocumentor\Reflection\Types\Boolean) {
114
            return 'bool';
115
        }
116
117 2
        if ($type instanceof \phpDocumentor\Reflection\Types\Callable_) {
118
            return 'callable';
119
        }
120
121 2
        if ($type instanceof \phpDocumentor\Reflection\Types\Float_) {
122
            return 'float';
123
        }
124
125 2
        if ($type instanceof \phpDocumentor\Reflection\Types\String_) {
126 2
            return 'string';
127
        }
128
129 1
        if ($type instanceof \phpDocumentor\Reflection\Types\Integer) {
130 1
            return 'int';
131
        }
132
133
        if ($type instanceof \phpDocumentor\Reflection\Types\Void_) {
134
            return 'void';
135
        }
136
137
        if ($type instanceof \phpDocumentor\Reflection\Types\Resource_) {
138
            return 'resource';
139
        }
140
141
        return $type . '';
142
    }
143
144
    /**
145
     * @param string $expectedTypes
146
     * @param mixed  $value
147
     * @param string $type
148
     *
149
     * @return \TypeError
150
     */
151 4
    public function throwException($expectedTypes, $value, $type): \Throwable
152
    {
153 4
        throw new \TypeError("Invalid type: expected \"{$this->property_name}\" to be of type {{$expectedTypes}}, instead got value \"" . $this->valueToString($value) . '" (' . \print_r($value, true) . ") with type {{$type}}.");
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with "Invalid type: expected ...) with type {{$type}}.".

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
154
    }
155
}
156