Passed
Push — visitor ( 06020c...45cf63 )
by Akihito
01:36
created

Container::isSingleton()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 7
rs 10
cc 4
nc 2
nop 1
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_key_exists;
17
use function array_merge;
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
        return $this->container[$index]->inject($this);
113
    }
114
115
    /**
116
     * Rename existing dependency interface + name
117
     */
118
    public function move(string $sourceInterface, string $sourceName, string $targetInterface, string $targetName): void
119
    {
120
        $sourceIndex = $sourceInterface . '-' . $sourceName;
121
        if (! isset($this->container[$sourceIndex])) {
122
            throw $this->unbound($sourceIndex);
123
        }
124
125
        $targetIndex = $targetInterface . '-' . $targetName;
126
        $this->container[$targetIndex] = $this->container[$sourceIndex];
127
        unset($this->container[$sourceIndex]);
128
    }
129
130
    /**
131
     * Return Unbound exception
132
     *
133
     * @param string $index {interface}-{bind name}
134
     *
135
     * @return Unbound|Untargeted
136
     */
137
    public function unbound(string $index)
138
    {
139
        [$class, $name] = explode('-', $index);
140
        if (class_exists($class) && ! (new ReflectionClass($class))->isAbstract()) {
141
            return new Untargeted($class);
142
        }
143
144
        return new Unbound("{$class}-{$name}");
145
    }
146
147
    /**
148
     * Return container
149
     *
150
     * @return DependencyInterface[]
151
     */
152
    public function getContainer(): array
153
    {
154
        return $this->container;
155
    }
156
157
    /**
158
     * Return pointcuts
159
     *
160
     * @return array<int, Pointcut>
161
     */
162
    public function getPointcuts(): array
163
    {
164
        return $this->pointcuts;
165
    }
166
167
    /**
168
     * Merge container
169
     */
170
    public function merge(self $container): void
171
    {
172
        $this->multiBindings->merge($container->multiBindings);
173
        $this->container += $container->getContainer();
174
        $this->pointcuts = array_merge($this->pointcuts, $container->getPointcuts());
175
    }
176
177
    /**
178
     * Weave aspects to all dependency in container
179
     */
180
    public function weaveAspects(CompilerInterface $compiler): void
181
    {
182
        foreach ($this->container as $dependency) {
183
            if ($dependency instanceof Dependency) {
184
                $dependency->weaveAspects($compiler, $this->pointcuts);
185
            }
186
        }
187
    }
188
189
    /**
190
     * Weave aspect to single dependency
191
     */
192
    public function weaveAspect(Compiler $compiler, Dependency $dependency): self
193
    {
194
        $dependency->weaveAspects($compiler, $this->pointcuts);
195
196
        return $this;
197
    }
198
199
    /**
200
     * @param callable(DependencyInterface): DependencyInterface $f
201
     */
202
    public function map(callable $f): void
203
    {
204
        foreach ($this->container as &$index) {
205
            $index = $f($index);
206
        }
207
    }
208
209
    public function sort(): void
210
    {
211
        ksort($this->container);
212
    }
213
}
214