Passed
Push — union-types ( cd7236...b93e9c )
by Luis
10:52
created

TypeDeclaration::isRegularType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * PHP version 8.0
4
 *
5
 * This source file is subject to the license that is bundled with this package in the file LICENSE.
6
 */
7
8
namespace PhUml\Code\Variables;
9
10
use PhUml\Code\Name;
11
use Stringable;
12
13
/**
14
 * It represents a variable's type declaration
15
 */
16
final class TypeDeclaration implements Stringable
17
{
18
    /** @var string[] All valid types for PHP 7.1, pseudo-types, and aliases */
19
    private const BUILT_IN_TYPES = [
20
        'int', 'bool', 'string', 'array', 'float', 'callable', 'iterable',
21
        // union types
22
        // https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.union.nullable
23
        'null',
24
        // pseudo-types
25
        'mixed', 'number', 'object', 'resource', 'self',
26
        // aliases
27
        'boolean', 'integer', 'double',
28
    ];
29
30
    /** @var Name[] */
31
    private array $names;
32
33
    public static function absent(): TypeDeclaration
34
    {
35
        return new TypeDeclaration();
36
    }
37
38
    public static function from(?string $type): TypeDeclaration
39
    {
40
        return new TypeDeclaration($type === null ? [] : [new Name($type)]);
41
    }
42
43
    public static function fromNullable(string $type): TypeDeclaration
44
    {
45
        return new TypeDeclaration([new Name($type)], isNullable: true);
46
    }
47
48
    /** @param string[] $types */
49
    public static function fromUnionType(array $types): TypeDeclaration
50
    {
51
        return new TypeDeclaration(array_map(static fn (string $type) => new Name($type), $types));
52
    }
53
54
    public function isPresent(): bool
55
    {
56
        return count($this->names) > 0;
57
    }
58
59
    /** @return Name[] */
60
    public function references(): array
61
    {
62
        if (! $this->isPresent()) {
63
            return [];
64
        }
65
        if ($this->isBuiltIn()) {
66
            return [];
67
        }
68
        if ($this->isRegularType()) {
69
            return [$this->isArray() ? new Name($this->removeArraySuffix()) : $this->names[0]];
70
        }
71
72
        $typesFromUnion = array_map(fn (Name $name) => TypeDeclaration::from((string) $name), $this->names);
73
        $references = array_filter($typesFromUnion, fn (TypeDeclaration $type) => ! $type->isBuiltIn());
74
75
        return array_map(
76
            fn (TypeDeclaration $reference) => $reference->isArray()
77
                ? new Name($reference->removeArraySuffix())
78
                : $reference->names[0],
79
            $references
80
        );
81
    }
82
83
    /**
84
     * It helps building the relationships between classes/interfaces since built-in
85
     * types are not part of a UML class diagram
86
     */
87
    public function isBuiltIn(): bool
88
    {
89
        if (! $this->isRegularType()) {
90
            return false;
91
        }
92
        $type = (string) $this->names[0];
93
        if ($this->isArray()) {
94
            $type = $this->removeArraySuffix();
95
        }
96
97
        return in_array($type, self::BUILT_IN_TYPES, true);
98
    }
99
100
    private function removeArraySuffix(): string
101
    {
102
        return substr((string) $this->names[0], 0, -2);
103
    }
104
105
    public function isBuiltInArray(): bool
106
    {
107
        if ($this->isRegularType()) {
108
            return (string) $this->names[0] === 'array';
109
        }
110
        return false;
111
    }
112
113
    private function isArray(): bool
114
    {
115
        return strpos((string) $this->names[0], '[]') === strlen((string) $this->names[0]) - 2;
116
    }
117
118
    public function isNullable(): bool
119
    {
120
        return $this->isNullable;
121
    }
122
123
    private function isRegularType(): bool
124
    {
125
        return count($this->names) === 1;
126
    }
127
128
    public function __toString(): string
129
    {
130
        return ($this->isNullable ? '?' : '') . implode('|', $this->names);
131
    }
132
133
    /** @param Name[] $names */
134
    private function __construct(array $names = [], private bool $isNullable = false)
135
    {
136
        $this->names = $names;
137
    }
138
}
139