Argument::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 19
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 19
c 0
b 0
f 0
rs 9.7666
cc 3
nc 4
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Di;
6
7
use ReflectionException;
8
use ReflectionMethod;
9
use ReflectionNamedType;
10
use ReflectionParameter;
11
use Serializable;
12
13
use function assert;
14
use function in_array;
15
use function serialize;
16
use function sprintf;
17
use function unserialize;
18
19
final class Argument implements Serializable, AcceptInterface
20
{
21
    public const UNBOUND_TYPE = ['bool', 'int', 'float', 'string', 'array', 'resource', 'callable', 'iterable'];
22
23
    /** @var string */
24
    private $index;
25
26
    /** @var bool */
27
    private $isDefaultAvailable;
28
29
    /** @var mixed */
30
    private $default;
31
32
    /** @var string */
33
    private $meta;
34
35
    /** @var ReflectionParameter */
36
    private $reflection;
37
38
    public function __construct(ReflectionParameter $parameter, string $name)
39
    {
40
        $type = $this->getType($parameter);
41
        $isOptional = $parameter->isOptional();
42
        $this->isDefaultAvailable = $parameter->isDefaultValueAvailable() || $isOptional;
43
        if ($isOptional) {
44
            $this->default = null;
45
        }
46
47
        $this->setDefaultValue($parameter);
48
        $this->index = $type . '-' . $name;
49
        $this->reflection = $parameter;
50
        $this->meta = sprintf(
51
            "dependency '%s' with name '%s' used in %s:%d ($%s)",
52
            $type,
53
            $name,
54
            $this->reflection->getDeclaringFunction()->getFileName(),
55
            $this->reflection->getDeclaringFunction()->getStartLine(),
56
            $parameter->getName()
57
        );
58
    }
59
60
    public function __toString(): string
61
    {
62
        return $this->index;
63
    }
64
65
    /**
66
     * Return reflection
67
     */
68
    public function get(): ReflectionParameter
69
    {
70
        return $this->reflection;
71
    }
72
73
    public function isDefaultAvailable(): bool
74
    {
75
        return $this->isDefaultAvailable;
76
    }
77
78
    /**
79
     * @return mixed
80
     */
81
    public function getDefaultValue()
82
    {
83
        return $this->default;
84
    }
85
86
    public function getMeta(): string
87
    {
88
        return $this->meta;
89
    }
90
91
    /**
92
     * {@inheritDoc}
93
     */
94
    public function serialize(): ?string
95
    {
96
        return serialize($this->__serialize());
97
    }
98
99
    /**
100
     * {@inheritDoc}
101
     *
102
     * @psalm-param string $data
103
     */
104
    public function unserialize($data): void
105
    {
106
        /** @var array{0: string, 1: bool, 2: string, 3: string, 4: string, 5: array{0: string, 1: string, 2:string}} $array */
107
        $array = unserialize($data, ['allowed_classes' => false]);
108
        $this->__unserialize($array);
109
    }
110
111
    /**
112
     * @return array<mixed>
113
     */
114
    public function __serialize(): array
115
    {
116
        $method = $this->reflection->getDeclaringFunction();
117
        assert($method instanceof ReflectionMethod);
118
        $ref = [
119
            $method->class,
120
            $method->name,
121
            $this->reflection->getName(),
122
        ];
123
124
        return [
125
            $this->index,
126
            $this->isDefaultAvailable,
127
            $this->default,
128
            $this->meta,
129
            $ref,
130
        ];
131
    }
132
133
    /**
134
     * @param array{0: string, 1: bool, 2: string, 3: string, 4: string, 5: array{0: string, 1: string, 2:string}} $unserialized
135
     */
136
    public function __unserialize(array $unserialized): void
137
    {
138
        [
139
            $this->index,
140
            $this->isDefaultAvailable,
141
            $this->default,
142
            $this->meta,
143
            $ref,
144
        ] = $unserialized;
145
        $this->reflection = new ReflectionParameter([$ref[0], $ref[1]], $ref[2]);
146
    }
147
148
    /** @inheritDoc */
149
    public function accept(VisitorInterface $visitor)
150
    {
151
        $visitor->visitArgument(
152
            $this->index,
153
            $this->isDefaultAvailable,
154
            $this->default,
155
            $this->reflection
156
        );
157
    }
158
159
    private function setDefaultValue(ReflectionParameter $parameter): void
160
    {
161
        if (! $this->isDefaultAvailable) {
162
            return;
163
        }
164
165
        try {
166
            $this->default = $parameter->getDefaultValue();
167
            // @codeCoverageIgnoreStart
168
        } catch (ReflectionException $e) {
169
            $this->default = null;
170
            // @codeCoverageIgnoreEnd
171
        }
172
    }
173
174
    private function getType(ReflectionParameter $parameter): string
175
    {
176
        $type = $parameter->getType();
177
178
        return $type instanceof ReflectionNamedType && ! in_array($type->getName(), self::UNBOUND_TYPE, true) ? $type->getName() : '';
179
    }
180
}
181