Completed
Push — master ( d5b9f3...8d51f3 )
by Lars
01:39
created

AbstractTypeCheck::isValidGenericCollection()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 2
dl 0
loc 16
ccs 8
cts 8
cp 1
crap 4
rs 9.7333
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arrayy\TypeCheck;
6
7
abstract class AbstractTypeCheck implements TypeCheckInterface
8
{
9
    /**
10
     * @var bool
11
     */
12
    protected $isNullable = false;
13
14
    /**
15
     * @var string[]
16
     */
17
    protected $types = [];
18
19
    /**
20
     * @var array<string, string>
21
     */
22
    private static $typeMapping = [
23
        'int'   => 'integer',
24
        'bool'  => 'boolean',
25
        'float' => 'double',
26
    ];
27
28
    /**
29
     * @return string[]
30
     */
31
    public function getTypes(): array
32
    {
33
        return $this->types;
34
    }
35
36
    /**
37
     * @param mixed $value
38
     *
39
     * @return bool
40
     */
41 99
    public function checkType(&$value): bool
42
    {
43 99
        if ($this->isNullable && $value === null) {
44 11
            return true;
45
        }
46
47 99
        foreach ($this->types as $currentType) {
48 99
            $isValidType = $this->assertTypeEquals($currentType, $value);
49
50 99
            if ($isValidType) {
51 97
                return true;
52
            }
53
        }
54
55 31
        $type = \gettype($value);
56
57 31
        $expectedTypes = \implode('|', $this->types);
58
59 31
        $this->throwException($expectedTypes, $value, $type);
60
61
        return false;
62
    }
63
64
    /**
65
     * @param string $type
66
     * @param mixed  $value
67
     *
68
     * @return bool
69
     */
70 99
    protected function assertTypeEquals(string $type, &$value): bool
71
    {
72 99
        if (\strpos($type, '[]') !== false) {
73 16
            return $this->isValidGenericCollection($type, $value);
74
        }
75
76 99
        if ($type === 'mixed' && $value !== null) {
77 4
            return true;
78
        }
79
80 99
        return $value instanceof $type
81
               ||
82 85
               \gettype($value) === (self::$typeMapping[$type] ?? $type)
83
               ||
84
               (
85 35
                   $type === 'scalar'
86
                    &&
87 35
                    \is_scalar($value)
88
               )
89
               ||
90
               (
91 34
                   $type === 'callable'
92
                   &&
93 34
                   \is_callable($value)
94
               )
95
               ||
96
               (
97 33
                   $type === 'numeric'
98
                   &&
99
                   (
100
                       \is_float($value)
101
                       ||
102 33
                       \is_int($value)
103
                   )
104
               )
105
               ||
106
               (
107 33
                   $type === 'resource'
108
                   &&
109 99
                   \is_resource($value)
110
               );
111
    }
112
113
    /**
114
     * @param mixed $value
115
     *
116
     * @return string
117
     */
118 4
    protected function valueToString($value): string
119
    {
120
        // null
121 4
        if ($value === null) {
122
            return 'NULL';
123
        }
124
125
        // bool
126 4
        if (\is_bool($value)) {
127
            return $value ? 'TRUE' : 'FALSE';
128
        }
129
130
        // array
131 4
        if (\is_array($value)) {
132 1
            return 'Array';
133
        }
134
135
        // scalar types (integer, float, string)
136 3
        if (\is_scalar($value)) {
137 2
            return (string) $value;
138
        }
139
140
        // resource
141 1
        if (\is_resource($value)) {
142
            return \get_resource_type($value) . ' resource #' . (int) $value;
143
        }
144
145 1
        if (\is_object($value)) {
146 1
            return \get_class($value) . ' Object';
147
        }
148
149
        return '';
150
    }
151
152
    /**
153
     * @param string $type
154
     * @param mixed  $collection
155
     *
156
     * @return bool
157
     */
158 16
    private function isValidGenericCollection(string $type, &$collection): bool
159
    {
160 16
        if (!\is_array($collection)) {
161 1
            return false;
162
        }
163
164 15
        $valueType = \str_replace('[]', '', $type);
165
166 15
        foreach ($collection as $value) {
167 15
            if ($this->assertTypeEquals($valueType, $value)) {
168 14
                return true;
169
            }
170
        }
171
172 2
        return false;
173
    }
174
}
175