Passed
Pull Request — 2.x (#264)
by Akihito
10:34 queued 13s
created

Container::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Di;
6
7
use BadMethodCallException;
8
use Ray\Aop\Compiler;
9
use Ray\Aop\CompilerInterface;
10
use Ray\Aop\Pointcut;
11
use Ray\Di\Exception\Unbound;
12
use Ray\Di\Exception\Untargeted;
13
use Ray\Di\MultiBinding\MultiBindings;
14
use ReflectionClass;
15
16
use function array_merge;
17
use function array_merge_recursive;
18
use function class_exists;
19
use function explode;
20
use function ksort;
21
22
final class Container implements InjectorInterface
23
{
24
    /** @var MultiBindings */
25
    public $multiBindings;
26
27
    /** @var DependencyInterface[] */
28
    private $container = [];
29
30
    /** @var array<int, Pointcut> */
31
    private $pointcuts = [];
32
33
    public function __construct()
34
    {
35
        $this->multiBindings = new MultiBindings();
36
    }
37
38
    /**
39
     * @return list<string>
0 ignored issues
show
Bug introduced by
The type Ray\Di\list 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...
40
     */
41
    public function __sleep()
42
    {
43
        return ['container', 'pointcuts', 'multiBindings'];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array('container'...cuts', 'multiBindings') returns the type array<integer,string> which is incompatible with the documented return type Ray\Di\list.
Loading history...
44
    }
45
46
    /**
47
     * Add binding to container
48
     */
49
    public function add(Bind $bind): void
50
    {
51
        $dependency = $bind->getBound();
52
        $dependency->register($this->container, $bind);
53
    }
54
55
    /**
56
     * Add Pointcut to container
57
     */
58
    public function addPointcut(Pointcut $pointcut): void
59
    {
60
        $this->pointcuts[] = $pointcut;
61
    }
62
63
    /**
64
     * {@inheritDoc}
65
     */
66
    public function getInstance($interface, $name = Name::ANY)
67
    {
68
        /**
69
         * @psalm-var T is object ? T : mixed
70
         * @phpstan-var mixed
71
         */
72
        return $this->getDependency($interface . '-' . $name);
73
    }
74
75
    /**
76
     * Return dependency injected instance
77
     *
78
     * @param array<int, mixed> $params
79
     *
80
     * @return mixed
81
     *
82
     * @throws Unbound
83
     */
84
    public function getInstanceWithArgs(string $interface, array $params)
85
    {
86
        $index = $interface . '-';
87
        if (! isset($this->container[$index])) {
88
            throw $this->unbound($index);
89
        }
90
91
        $dependency = $this->container[$index];
92
        if (! $dependency instanceof Dependency) {
93
            throw new BadMethodCallException($interface);
94
        }
95
96
        return $dependency->injectWithArgs($this, $params);
97
    }
98
99
    /**
100
     * Return dependency injected instance
101
     *
102
     * @return mixed
103
     *
104
     * @throws Unbound
105
     */
106
    public function getDependency(string $index)
107
    {
108
        if (! isset($this->container[$index])) {
109
            throw $this->unbound($index);
110
        }
111
112
        $dependency = $this->container[$index];
113
114
        return $dependency->inject($this);
115
    }
116
117
    /**
118
     * Rename existing dependency interface + name
119
     */
120
    public function move(string $sourceInterface, string $sourceName, string $targetInterface, string $targetName): void
121
    {
122
        $sourceIndex = $sourceInterface . '-' . $sourceName;
123
        if (! isset($this->container[$sourceIndex])) {
124
            throw $this->unbound($sourceIndex);
125
        }
126
127
        $targetIndex = $targetInterface . '-' . $targetName;
128
        $this->container[$targetIndex] = $this->container[$sourceIndex];
129
        unset($this->container[$sourceIndex]);
130
    }
131
132
    /**
133
     * Return Unbound exception
134
     *
135
     * @param string $index {interface}-{bind name}
136
     *
137
     * @return Unbound|Untargeted
138
     */
139
    public function unbound(string $index)
140
    {
141
        [$class, $name] = explode('-', $index);
142
        if (class_exists($class) && ! (new ReflectionClass($class))->isAbstract()) {
143
            return new Untargeted($class);
144
        }
145
146
        return new Unbound("{$class}-{$name}");
147
    }
148
149
    /**
150
     * Return container
151
     *
152
     * @return DependencyInterface[]
153
     */
154
    public function getContainer(): array
155
    {
156
        return $this->container;
157
    }
158
159
    /**
160
     * Return pointcuts
161
     *
162
     * @return array<int, Pointcut>
163
     */
164
    public function getPointcuts(): array
165
    {
166
        return $this->pointcuts;
167
    }
168
169
    /**
170
     * Merge container
171
     */
172
    public function merge(self $container): void
173
    {
174
        $mergedLazyCollection = array_merge_recursive($this->multiBindings->getArrayCopy(), $container->multiBindings->getArrayCopy());
175
        $this->multiBindings->exchangeArray($mergedLazyCollection);
176
        $this->container += $container->getContainer();
177
        $this->pointcuts = array_merge($this->pointcuts, $container->getPointcuts());
178
    }
179
180
    /**
181
     * Weave aspects to all dependency in container
182
     */
183
    public function weaveAspects(CompilerInterface $compiler): void
184
    {
185
        foreach ($this->container as $dependency) {
186
            if ($dependency instanceof Dependency) {
187
                $dependency->weaveAspects($compiler, $this->pointcuts);
188
            }
189
        }
190
    }
191
192
    /**
193
     * Weave aspect to single dependency
194
     */
195
    public function weaveAspect(Compiler $compiler, Dependency $dependency): self
196
    {
197
        $dependency->weaveAspects($compiler, $this->pointcuts);
198
199
        return $this;
200
    }
201
202
    /**
203
     * @param callable(DependencyInterface): DependencyInterface $f
204
     */
205
    public function map(callable $f): void
206
    {
207
        foreach ($this->container as &$index) {
208
            $index = $f($index);
209
        }
210
    }
211
212
    public function sort(): void
213
    {
214
        ksort($this->container);
215
    }
216
}
217