Passed
Pull Request — master (#63)
by Aleksei
02:16
created

ResolvingState::addResolvedValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Injector;
6
7
use Generator;
8
use ReflectionFunctionAbstract;
9
10
/**
11
 * Intermediate arguments resolving data to pass around until resolving is finished.
12
 *
13
 * @internal
14
 */
15
final class ResolvingState
16
{
17
    private ReflectionFunctionAbstract $reflection;
18
19
    /**
20
     * @psalm-var array<int, object>
21
     */
22
    private array $numericArguments = [];
23
24
    /**
25
     * @psalm-var array<string, mixed>
26
     */
27
    private array $namedArguments = [];
28
29
    private bool $shouldPushTrailingArguments;
30
31
    /**
32
     * @psalm-var list<mixed>
33
     */
34
    private array $resolvedValues = [];
35
36
    /**
37
     * @param ReflectionFunctionAbstract $reflection Function reflection.
38
     * @param array $arguments User arguments.
39
     */
40 50
    public function __construct(ReflectionFunctionAbstract $reflection, array $arguments)
41
    {
42 50
        $this->reflection = $reflection;
43 50
        $this->shouldPushTrailingArguments = !$reflection->isInternal();
44 50
        $this->sortArguments($arguments);
45
    }
46
47
    public function hasNamedArgument(string $name): bool
48
    {
49
        return array_key_exists($name, $this->namedArguments);
50
    }
51
52
    /**
53
     * @param bool $condition If true then trailing arguments will not be passed.
54
     */
55 39
    public function disablePushTrailingArguments(bool $condition): void
56
    {
57 39
        $this->shouldPushTrailingArguments = $this->shouldPushTrailingArguments && !$condition;
58
    }
59
60
    /**
61
     * @param mixed $value
62
     */
63 33
    public function addResolvedValue(&$value): void
64
    {
65 33
        $this->resolvedValues[] = &$value;
66
    }
67
68 39
    public function resolveParameterByName(string $name, bool $variadic): bool
69
    {
70 39
        if (!array_key_exists($name, $this->namedArguments)) {
71 33
            return false;
72
        }
73 12
        if ($variadic && is_array($this->namedArguments[$name])) {
74 2
            array_walk($this->namedArguments[$name], [$this, 'addResolvedValue']);
75
        } else {
76 11
            $this->addResolvedValue($this->namedArguments[$name]);
77
        }
78 12
        return true;
79
    }
80
81
    /**
82
     * @psalm-param class-string|null $className
83
     */
84 27
    public function resolveParameterByClass(?string $className, bool $variadic): bool
85
    {
86 27
        $generator = $this->pullNumericArgument($className);
87 27
        if (!$variadic) {
88 23
            if (!$generator->valid()) {
89 20
                return false;
90
            }
91 7
            $value = $generator->current();
92 7
            $this->addResolvedValue($value);
93 7
            return true;
94
        }
95 7
        foreach ($generator as &$value) {
96 5
            $this->addResolvedValue($value);
97
        }
98 7
        return true;
99
    }
100
101 41
    public function getResolvedValues(): array
102
    {
103 41
        return $this->shouldPushTrailingArguments
104 26
            ? [...$this->resolvedValues, ...$this->numericArguments]
105 41
            : $this->resolvedValues;
106
    }
107
108
    /**
109
     * @psalm-param class-string|null $className
110
     *
111
     * @psalm-return Generator<int, object, mixed, void>
112
     */
113 27
    private function &pullNumericArgument(?string $className): Generator
114
    {
115 27
        foreach ($this->numericArguments as $key => &$value) {
116 12
            if ($className === null || $value instanceof $className) {
117 11
                unset($this->numericArguments[$key]);
118 11
                yield $value;
119
            }
120
        }
121
    }
122
123
    /**
124
     * @param array $arguments
125
     *
126
     * @throws InvalidArgumentException
127
     */
128 50
    private function sortArguments(array $arguments): void
129
    {
130 50
        foreach ($arguments as $key => &$value) {
131 27
            if (is_int($key)) {
132 20
                if (!is_object($value)) {
133 3
                    throw new InvalidArgumentException($this->reflection, (string)$key);
134
                }
135 17
                $this->numericArguments[] = &$value;
136
            } else {
137 14
                $this->namedArguments[$key] = &$value;
138
            }
139
        }
140
    }
141
}
142