-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathContainer.php
More file actions
239 lines (205 loc) · 6.2 KB
/
Container.php
File metadata and controls
239 lines (205 loc) · 6.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
<?php
/*
* This file is part of the PHPBench package
*
* (c) Daniel Leech <daniel@dantleech.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PhpBench\DependencyInjection;
use Interop\Container\ContainerInterface;
/**
* PHPBench Container.
*
* This is a simple, extendable, closure based dependency injection container.
*/
class Container implements ContainerInterface
{
private $instantiators = [];
private $services = [];
private $tags = [];
private $config = [];
private $userConfig = [];
private $extensionClasses = [];
public function __construct(array $extensionClasses = [], array $userConfig = [])
{
$this->extensionClasses = $extensionClasses;
$this->userConfig = $userConfig;
}
/**
* Configure the container. This method will call the `configure()` method
* on each extension. Extensions must use this opportunity to register their
* services and define any default config.
*
* This method must be called before `build()`.
*/
public function init()
{
$extensions = [];
if (empty($this->extensionClasses) && empty($this->userConfig)) {
return;
}
foreach ($this->extensionClasses as $extensionClass) {
if (!class_exists($extensionClass)) {
throw new \InvalidArgumentException(sprintf(
'Extension class "%s" does not exist',
$extensionClass
));
}
$extension = new $extensionClass();
if (!$extension instanceof ExtensionInterface) {
throw new \InvalidArgumentException(sprintf(
// add any manually specified extensions
'Extension "%s" must implement the PhpBench\\Extension interface',
get_class($extension)
));
}
$extensions[] = $extension;
$this->config = array_merge(
$this->config,
$extension->getDefaultConfig()
);
}
$diff = array_diff(array_keys($this->userConfig), array_keys($this->config));
if ($diff) {
throw new \InvalidArgumentException(sprintf(
'Unknown configuration keys: "%s". Permitted keys: "%s"',
implode('", "', $diff), implode('", "', array_keys($this->config))
));
}
$this->config = array_merge(
$this->config,
$this->userConfig
);
foreach ($extensions as $extension) {
$extension->load($this);
}
}
/**
* Instantiate and return the service with the given ID.
* Note that this method will return the same instance on subsequent calls.
*
* @param string $serviceId
*
* @return mixed
*/
public function get($serviceId)
{
if (isset($this->services[$serviceId])) {
return $this->services[$serviceId];
}
if (!isset($this->instantiators[$serviceId])) {
throw new \InvalidArgumentException(sprintf(
'No instantiator has been registered for requested service "%s"',
$serviceId
));
}
$this->services[$serviceId] = $this->instantiators[$serviceId]($this);
return $this->services[$serviceId];
}
public function has($serviceId)
{
return isset($this->instantiators[$serviceId]);
}
/**
* Set a service instance.
*
* @param string $serviceId
* @param mixed $instance
*/
public function set($serviceId, $instance)
{
$this->services[$serviceId] = $instance;
}
/**
* Return services IDs for the given tag.
*
* @param string $tag
*
* @return string[]
*/
public function getServiceIdsForTag($tag)
{
$serviceIds = [];
foreach ($this->tags as $serviceId => $tags) {
if (isset($tags[$tag])) {
$serviceIds[$serviceId] = $tags[$tag];
}
}
return $serviceIds;
}
/**
* Register a service with the given ID and instantiator.
*
* The instantiator is a closure which accepts an instance of this container and
* returns a new instance of the service class.
*
* @param string $serviceId
* @param \Closure $instantiator
* @param string[] $tags
*/
public function register($serviceId, \Closure $instantiator, array $tags = [])
{
if (isset($this->instantiators[$serviceId])) {
throw new \InvalidArgumentException(sprintf(
'Service with ID "%s" has already been registered', $serviceId));
}
$this->instantiators[$serviceId] = $instantiator;
$this->tags[$serviceId] = $tags;
}
/**
* Set the value of the parameter with the given name.
*
* @param string $name
* @param mixed $value
*/
public function setParameter($name, $value)
{
$this->config[$name] = $value;
}
public function mergeParameter($name, array $values)
{
$actual = $this->getParameter($name);
if (!is_array($actual)) {
throw new \InvalidArgumentException(sprintf(
'Cannot merge values on to a scalar parameter "%s"',
$name
));
}
$this->setParameter($name, array_merge(
$actual,
$values
));
}
/**
* Return the parameter with the given name.
*
* @param string $name
*
* @throws \InvalidArgumentException
*
* @return mixed
*/
public function getParameter($name)
{
if (!array_key_exists($name, $this->config)) {
throw new \InvalidArgumentException(sprintf(
'Parameter "%s" has not been registered',
$name
));
}
return $this->config[$name];
}
/**
* Return true if the named parameter exists.
*
* @param string $name
*
* @return bool
*/
public function hasParameter($name)
{
return array_key_exists($name, $this->config);
}
}