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