Container::bound()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Magister\Services\Container;
4
5
use ArrayAccess;
6
use Closure;
7
use InvalidArgumentException;
8
use Magister\Services\Contracts\Container\Container as ContainerContract;
9
10
/**
11
 * Class Container.
12
 */
13
class Container implements ArrayAccess, ContainerContract
14
{
15
    /**
16
     * The container's bindings.
17
     *
18
     * @var array
19
     */
20
    protected $bindings = [];
21
22
    /**
23
     * Register a binding with the container.
24
     *
25
     * @param string $abstract
26
     * @param mixed  $concrete
27
     *
28
     * @return void
29
     */
30
    public function bind($abstract, $concrete)
31
    {
32
        $this->bindings[$abstract] = $concrete;
33
    }
34
35
    /**
36
     * Register a service as a singleton.
37
     *
38
     * @param string $abstract
39
     * @param mixed  $concrete
40
     *
41
     * @return void
42
     */
43
    public function singleton($abstract, $concrete)
44
    {
45
        $this->bind($abstract, $this->share($concrete));
46
    }
47
48
    /**
49
     * Resolve the given type from the container.
50
     *
51
     * @param string $abstract
52
     *
53
     * @throws \InvalidArgumentException
54
     *
55
     * @return mixed
56
     */
57
    public function make($abstract)
58
    {
59
        if (!$this->bound($abstract)) {
60
            throw new InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $abstract));
61
        }
62
63
        $isFactory = is_object($this->bindings[$abstract]) && method_exists($this->bindings[$abstract], '__invoke');
64
65
        return $isFactory ? $this->bindings[$abstract]($this) : $this->bindings[$abstract];
66
    }
67
68
    /**
69
     * Determine if the given abstract type has been bound.
70
     *
71
     * @param string $abstract
72
     *
73
     * @return bool
74
     */
75
    public function bound($abstract)
76
    {
77
        return array_key_exists($abstract, $this->bindings);
78
    }
79
80
    /**
81
     * Remove the specified abstract from the container.
82
     *
83
     * @param string $abstract
84
     *
85
     * @return void
86
     */
87
    public function remove($abstract)
88
    {
89
        unset($this->bindings[$abstract]);
90
    }
91
92
    /**
93
     * Returns a closure that stores the result of the given closure for
94
     * uniqueness in the scope of this instance of the container.
95
     *
96
     * @param \Closure $callable
97
     *
98
     * @return \Closure
99
     */
100
    public static function share(Closure $callable)
101
    {
102
        return function ($c) use ($callable) {
103
            static $object;
104
105
            if (null === $object) {
106
                $object = $callable($c);
107
            }
108
109
            return $object;
110
        };
111
    }
112
113
    /**
114
     * Protects a callable from being interpreted as a service.
115
     *
116
     * @param \Closure $callable
117
     *
118
     * @return \Closure
119
     */
120
    public static function protect(Closure $callable)
121
    {
122
        return function ($c) use ($callable) {
0 ignored issues
show
Unused Code introduced by
The parameter $c is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
123
            return $callable;
124
        };
125
    }
126
127
    /**
128
     * Gets a parameter or the closure defining an object.
129
     *
130
     * @param string $abstract
131
     *
132
     * @throws \InvalidArgumentException
133
     *
134
     * @return mixed
135
     */
136
    public function raw($abstract)
137
    {
138
        if (!array_key_exists($abstract, $this->bindings)) {
139
            throw new InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $abstract));
140
        }
141
142
        return $this->bindings[$abstract];
143
    }
144
145
    /**
146
     * Extends an object definition.
147
     *
148
     * @param string   $abstract
149
     * @param \Closure $callable
150
     *
151
     * @throws \InvalidArgumentException
152
     *
153
     * @return \Closure
154
     */
155
    public function extend($abstract, Closure $callable)
156
    {
157
        if (!array_key_exists($abstract, $this->bindings)) {
158
            throw new InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $abstract));
159
        }
160
161
        $factory = $this->bindings[$abstract];
162
163
        if (!($factory instanceof Closure)) {
164
            throw new InvalidArgumentException(sprintf('Identifier "%s" does not contain an object definition.', $abstract));
165
        }
166
167
        return $this->bindings[$abstract] = function ($c) use ($callable, $factory) {
168
            return $callable($factory($c), $c);
169
        };
170
    }
171
172
    /**
173
     * Returns all defined value names.
174
     *
175
     * @return array
176
     */
177
    public function keys()
178
    {
179
        return array_keys($this->bindings);
180
    }
181
182
    /**
183
     * Register a binding with the container.
184
     *
185
     * @param string $abstract
186
     * @param mixed  $concrete
187
     *
188
     * @return void
189
     */
190
    public function __set($abstract, $concrete)
191
    {
192
        $this->bind($abstract, $concrete);
193
    }
194
195
    /**
196
     * Resolve the given type from the container.
197
     *
198
     * @param string $abstract
199
     *
200
     * @return mixed
201
     */
202
    public function __get($abstract)
203
    {
204
        return $this->make($abstract);
205
    }
206
207
    /**
208
     * Determine if the given abstract type has been bound.
209
     *
210
     * @param string $abstract
211
     *
212
     * @return bool
213
     */
214
    public function __isset($abstract)
215
    {
216
        $this->bound($abstract);
217
    }
218
219
    /**
220
     * Remove the specified abstract from the container.
221
     *
222
     * @param string $abstract
223
     *
224
     * @return void
225
     */
226
    public function __unset($abstract)
227
    {
228
        $this->remove($abstract);
229
    }
230
231
    /**
232
     * Register a binding with the container.
233
     *
234
     * @param string $abstract
235
     * @param mixed  $concrete
236
     *
237
     * @return void
238
     */
239
    public function offsetSet($abstract, $concrete)
240
    {
241
        $this->bind($abstract, $concrete);
242
    }
243
244
    /**
245
     * Resolve the given type from the container.
246
     *
247
     * @param string $abstract
248
     *
249
     * @return mixed
250
     */
251
    public function offsetGet($abstract)
252
    {
253
        return $this->make($abstract);
254
    }
255
256
    /**
257
     * Determine if the given abstract type has been bound.
258
     *
259
     * @param string $abstract
260
     *
261
     * @return bool
262
     */
263
    public function offsetExists($abstract)
264
    {
265
        $this->bound($abstract);
266
    }
267
268
    /**
269
     * Remove the specified abstract from the container.
270
     *
271
     * @param string $abstract
272
     *
273
     * @return void
274
     */
275
    public function offsetUnset($abstract)
276
    {
277
        $this->remove($abstract);
278
    }
279
}
280