Passed
Pull Request — master (#28)
by Aleksei
10:32
created

ResolvingState::resolveParamByClass()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
c 0
b 0
f 0
nc 4
nop 2
dl 0
loc 15
rs 9.9332
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Injector;
6
7
use Generator;
8
use ReflectionFunctionAbstract;
9
10
final class ResolvingState
11
{
12
    private ReflectionFunctionAbstract $reflection;
13
    /** @var array<int, object> */
14
    private array $numericArgs = [];
15
    /** @var array<string, mixed> */
16
    private array $namedArgs = [];
17
    private bool $isPushTrailedArguments;
18
    private array $resolvedValues = [];
19
20
    /**
21
     * @param ReflectionFunctionAbstract $reflection function reflection.
22
     * @param array $arguments user arguments.
23
     */
24
    public function __construct(ReflectionFunctionAbstract $reflection, array $arguments)
25
    {
26
        $this->reflection = $reflection;
27
        $this->isPushTrailedArguments = !$reflection->isInternal();
28
        $this->sortArguments($arguments);
29
    }
30
31
    public function hasNamedArgument(string $name): bool
32
    {
33
        return array_key_exists($name, $this->namedArgs);
34
    }
35
36
    /**
37
     * @param bool $condition If true then trailed arguments will not be passed
38
     */
39
    public function disableTrailedArguments(bool $condition): void
40
    {
41
        $this->isPushTrailedArguments = $this->isPushTrailedArguments && !$condition;
42
    }
43
44
    public function addResolvedValue(&$value): void
45
    {
46
        $this->resolvedValues[] = &$value;
47
    }
48
    public function resolveParamByName(string $name, bool $variadic): bool
49
    {
50
        if (!array_key_exists($name, $this->namedArgs)) {
51
            return false;
52
        }
53
        if ($variadic && is_array($this->namedArgs[$name])) {
54
            array_walk($this->namedArgs[$name], [$this, 'addResolvedValue']);
55
        } else {
56
            $this->addResolvedValue($this->namedArgs[$name]);
57
        }
58
        return true;
59
    }
60
    public function resolveParamByClass(?string $className, bool $variadic): bool
61
    {
62
        $generator = $this->pullNumericArg($className);
63
        if (!$variadic) {
64
            if (!$generator->valid()) {
65
                return false;
66
            }
67
            $value = $generator->current();
68
            $this->addResolvedValue($value);
69
            return true;
70
        }
71
        foreach ($generator as &$value) {
72
            $this->addResolvedValue($value);
73
        }
74
        return true;
75
    }
76
77
    public function getResolvedValues(): array
78
    {
79
        return $this->isPushTrailedArguments
80
            ? [...$this->resolvedValues, ...$this->numericArgs]
81
            : $this->resolvedValues;
82
    }
83
84
    /**
85
     * @param null|string $className
86
     * @return Generator<void, object>
87
     */
88
    private function &pullNumericArg(?string $className): Generator
89
    {
90
        foreach ($this->numericArgs as $key => &$value) {
91
            if ($className === null || $value instanceof $className) {
92
                unset($this->numericArgs[$key]);
93
                yield $value;
94
            }
95
        }
96
    }
97
    /**
98
     * @param array $arguments
99
     * @throws InvalidArgumentException
100
     */
101
    private function sortArguments(array $arguments): void
102
    {
103
        foreach ($arguments as $key => &$value) {
104
            if (is_int($key)) {
105
                if (!is_object($value)) {
106
                    throw new InvalidArgumentException($this->reflection, (string)$key);
107
                }
108
                $this->numericArgs[] = &$value;
109
            } else {
110
                $this->namedArgs[$key] = &$value;
111
            }
112
        }
113
    }
114
}
115