Issues (101)

src/di/Argument.php (2 issues)

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
/**
20
 * @psalm-import-type DependencyIndex from Types
21
 */
22
final class Argument implements Serializable, AcceptInterface
23
{
24
    public const UNBOUND_TYPE = ['bool', 'int', 'float', 'string', 'array', 'resource', 'callable', 'iterable'];
25
26
    /** @var DependencyIndex */
0 ignored issues
show
The type Ray\Di\DependencyIndex was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
    private $index;
28
29
    /** @var bool */
30
    private $isDefaultAvailable;
31
32
    /** @var mixed */
33
    private $default;
34
35
    /** @var string */
36
    private $meta;
37
38
    /** @var ReflectionParameter */
39
    private $reflection;
40
41
    public function __construct(ReflectionParameter $parameter, string $name)
42
    {
43
        $type = $this->getType($parameter);
44
        $isOptional = $parameter->isOptional();
45
        $this->isDefaultAvailable = $parameter->isDefaultValueAvailable() || $isOptional;
46
        if ($isOptional) {
47
            $this->default = null;
48
        }
49
50
        $this->setDefaultValue($parameter);
51
        $this->index = $type . '-' . $name;
0 ignored issues
show
Documentation Bug introduced by
It seems like $type . '-' . $name of type string is incompatible with the declared type Ray\Di\DependencyIndex of property $index.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
52
        $this->reflection = $parameter;
53
        $this->meta = sprintf(
54
            "dependency '%s' with name '%s' used in %s:%d ($%s)",
55
            $type,
56
            $name,
57
            $this->reflection->getDeclaringFunction()->getFileName(),
58
            $this->reflection->getDeclaringFunction()->getStartLine(),
59
            $parameter->getName()
60
        );
61
    }
62
63
    /**
64
     * Return index
65
     *
66
     * @return DependencyIndex
67
     */
68
    public function __toString(): string
69
    {
70
        return $this->index;
71
    }
72
73
    /**
74
     * Return reflection
75
     */
76
    public function get(): ReflectionParameter
77
    {
78
        return $this->reflection;
79
    }
80
81
    public function isDefaultAvailable(): bool
82
    {
83
        return $this->isDefaultAvailable;
84
    }
85
86
    /**
87
     * @return mixed
88
     */
89
    public function getDefaultValue()
90
    {
91
        return $this->default;
92
    }
93
94
    public function getMeta(): string
95
    {
96
        return $this->meta;
97
    }
98
99
    /**
100
     * {@inheritDoc}
101
     */
102
    public function serialize(): ?string // @phpstan-ignore-line
103
    {
104
        return serialize($this->__serialize());
105
    }
106
107
    /**
108
     * {@inheritDoc}
109
     *
110
     * @psalm-param string $data
111
     */
112
    public function unserialize($data): void
113
    {
114
        /** @var array{0: DependencyIndex, 1: bool, 2: string, 3: string, 4: string, 5: array{0: string, 1: string, 2:string}} $array */
115
        $array = unserialize($data, ['allowed_classes' => false]);
116
        $this->__unserialize($array);
117
    }
118
119
    /**
120
     * @return array<mixed>
121
     */
122
    public function __serialize(): array
123
    {
124
        $method = $this->reflection->getDeclaringFunction();
125
        assert($method instanceof ReflectionMethod);
126
        $ref = [
127
            $method->class,
128
            $method->name,
129
            $this->reflection->getName(),
130
        ];
131
132
        return [
133
            $this->index,
134
            $this->isDefaultAvailable,
135
            $this->default,
136
            $this->meta,
137
            $ref,
138
        ];
139
    }
140
141
    /**
142
     * @param array{0: DependencyIndex, 1: bool, 2: string, 3: string, 4: string, 5: array{0: string, 1: string, 2:string}} $unserialized
143
     */
144
    public function __unserialize(array $unserialized): void
145
    {
146
        [
147
            $this->index,
148
            $this->isDefaultAvailable,
149
            $this->default,
150
            $this->meta,
151
            $ref,
152
        ] = $unserialized;
153
        $this->reflection = new ReflectionParameter([$ref[0], $ref[1]], $ref[2]);
154
    }
155
156
    /** @inheritDoc */
157
    public function accept(VisitorInterface $visitor)
158
    {
159
        $visitor->visitArgument(
160
            $this->index,
161
            $this->isDefaultAvailable,
162
            $this->default,
163
            $this->reflection
164
        );
165
    }
166
167
    private function setDefaultValue(ReflectionParameter $parameter): void
168
    {
169
        if (! $this->isDefaultAvailable) {
170
            return;
171
        }
172
173
        try {
174
            $this->default = $parameter->getDefaultValue();
175
            // @codeCoverageIgnoreStart
176
        } catch (ReflectionException $e) {
177
            $this->default = null;
178
            // @codeCoverageIgnoreEnd
179
        }
180
    }
181
182
    /**
183
     * @psalm-pure
184
     */
185
    private function getType(ReflectionParameter $parameter): string
186
    {
187
        $type = $parameter->getType();
188
189
        return $type instanceof ReflectionNamedType && ! in_array($type->getName(), self::UNBOUND_TYPE, true) ? $type->getName() : '';
190
    }
191
}
192