Test Failed
Push — master ( dbe410...b8c007 )
by Kirill
02:19
created

Type::instanceOf()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
/**
3
 * This file is part of Railt package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace Railt\Reflection;
11
12
use Railt\Reflection\Common\Serializable;
13
use Railt\Reflection\Contracts\Definition\Behaviour\ProvidesType;
14
use Railt\Reflection\Contracts\Definition\TypeDefinition;
15
use Railt\Reflection\Contracts\Type as TypeInterface;
16
use Railt\Reflection\Exception\ReflectionException;
17
use Railt\Reflection\Exception\TypeConflictException;
18
19
/**
20
 * Class Type
21
 */
22
class Type implements TypeInterface
23
{
24
    use Serializable;
25
26
    /**
27
     * @var Type[]
28
     */
29
    private static $instances = [];
30
31
    /**
32
     * @var array[]|string[][]
33
     */
34
    private static $inheritance = [];
35
36
    /**
37
     * @var array|string[]
38
     */
39
    private $parent;
40
41
    /**
42
     * @var string
43
     */
44
    protected $name;
45
46
    /**
47
     * BaseType constructor.
48
     * @param string $name
49
     * @throws \Railt\Io\Exception\ExternalFileException
50
     */
51 9
    private function __construct(string $name)
52
    {
53 9
        $this->name = $name;
54 9
        $this->parent = $this->getInheritanceSequence($name);
55
56 9
        $this->verifyType($name);
57 9
    }
58
59
    /**
60
     * @param string $name
61
     * @throws \Railt\Io\Exception\ExternalFileException
62
     */
63 9 View Code Duplication
    private function verifyType(string $name): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
64
    {
65 9
        $types = \array_merge(static::DEPENDENT_TYPES, static::ROOT_TYPES);
66
67 9
        if (! \in_array($name, $types, true)) {
68
            throw new TypeConflictException(\sprintf('Invalid type name %s', $this));
69
        }
70 9
    }
71
72
    /**
73
     * @return bool
74
     */
75 9
    public function isInputable(): bool
76
    {
77 9
        return \in_array($this->name, static::ALLOWS_TO_INPUT, true);
78
    }
79
80
    /**
81
     * @return bool
82
     */
83
    public function isReturnable(): bool
84
    {
85
        return \in_array($this->name, static::ALLOWS_TO_OUTPUT, true);
86
    }
87
88
    /**
89
     * @param string $name
90
     * @return array
91
     */
92 9
    private function getInheritanceSequence(string $name): array
93
    {
94 9
        if (self::$inheritance === []) {
95
            $this->bootInheritance(new \SplStack(), static::INHERITANCE_TREE);
96
        }
97
98 9
        return self::$inheritance[$name] ?? [static::ROOT_TYPE];
99
    }
100
101
    /**
102
     * @param \SplStack $stack
103
     * @param array $children
104
     */
105
    private function bootInheritance(\SplStack $stack, array $children = []): void
106
    {
107
        $push = function (string $type) use ($stack): void {
108
            self::$inheritance[$type] = \array_values(\iterator_to_array($stack));
109
            self::$inheritance[$type][] = static::ROOT_TYPE;
110
111
            $stack->push($type);
112
        };
113
114
        foreach ($children as $type => $child) {
115
            switch (true) {
116
                case \is_string($child):
117
                    $push($child);
118
                    break;
119
120
                case \is_array($child):
121
                    $push($type);
122
                    $this->bootInheritance($stack, $child);
123
                    break;
124
            }
125
126
            $stack->pop();
127
        }
128
    }
129
130
    /**
131
     * @param string|ProvidesType $type
132
     * @return Type|\Railt\Reflection\Contracts\Type
133
     * @throws \Railt\Io\Exception\ExternalFileException
134
     */
135 171
    public static function of($type): Type
136
    {
137
        switch (true) {
138 171
            case \is_string($type):
139 171
                return self::$instances[$type] ?? (self::$instances[$type] = new static($type));
140
141
            case $type instanceof ProvidesType:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
142
                return $type::getType();
143
144
            default:
0 ignored issues
show
Coding Style introduced by
DEFAULT statements must be defined using a colon

As per the PSR-2 coding standard, default statements should not be wrapped in curly braces.

switch ($expr) {
    default: { //wrong
        doSomething();
        break;
    }
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
145
                throw new ReflectionException('Unsupported argument type');
146
        }
147
    }
148
149
    /**
150
     * @return bool
151
     */
152
    public function isDependent(): bool
153
    {
154
        return \in_array($this->name, static::DEPENDENT_TYPES, true);
155
    }
156
157
    /**
158
     * @param TypeInterface $type
159
     * @return bool
160
     */
161 90
    public function instanceOf(TypeInterface $type): bool
162
    {
163 90
        $needle = $type->getName();
164
165 90
        return $this->is($needle) || \in_array($needle, $this->parent, true);
166
    }
167
168
    /**
169
     * @param string $type
170
     * @return bool
171
     */
172 171
    public function is(string $type): bool
173
    {
174 171
        return $this->getName() === $type;
175
    }
176
177
    /**
178
     * @return string
179
     */
180 171
    public function getName(): string
181
    {
182 171
        return $this->name;
183
    }
184
185
    /**
186
     * @return string
187
     */
188 146
    public function __toString(): string
189
    {
190 146
        return $this->getName();
191
    }
192
}
193