Skip to content

Latest commit

 

History

History
305 lines (266 loc) · 9.22 KB

File metadata and controls

305 lines (266 loc) · 9.22 KB
 
Apr 29, 2014
Apr 29, 2014
1
<?php
2
3
/*
4
* This file is part of Pimple.
5
*
6
* Copyright (c) 2009 Fabien Potencier
7
*
8
* Permission is hereby granted, free of charge, to any person obtaining a copy
9
* of this software and associated documentation files (the "Software"), to deal
10
* in the Software without restriction, including without limitation the rights
11
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
* copies of the Software, and to permit persons to whom the Software is furnished
13
* to do so, subject to the following conditions:
14
*
15
* The above copyright notice and this permission notice shall be included in all
16
* copies or substantial portions of the Software.
17
*
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
* THE SOFTWARE.
25
*/
26
27
namespace Pimple;
28
Jul 3, 2017
Jul 3, 2017
29
use Pimple\Exception\ExpectedInvokableException;
30
use Pimple\Exception\FrozenServiceException;
31
use Pimple\Exception\InvalidServiceIdentifierException;
32
use Pimple\Exception\UnknownIdentifierException;
33
Apr 29, 2014
Apr 29, 2014
34
/**
35
* Container main class.
36
*
Jul 7, 2017
Jul 7, 2017
37
* @author Fabien Potencier
Apr 29, 2014
Apr 29, 2014
38
*/
39
class Container implements \ArrayAccess
40
{
Mar 3, 2020
Mar 3, 2020
41
private $values = [];
Apr 29, 2014
Apr 29, 2014
42
private $factories;
43
private $protected;
Mar 3, 2020
Mar 3, 2020
44
private $frozen = [];
45
private $raw = [];
46
private $keys = [];
Apr 29, 2014
Apr 29, 2014
47
48
/**
Jul 7, 2017
Jul 7, 2017
49
* Instantiates the container.
Apr 29, 2014
Apr 29, 2014
50
*
51
* Objects and parameters can be passed as argument to the constructor.
52
*
Jul 3, 2017
Jul 3, 2017
53
* @param array $values The parameters or objects
Apr 29, 2014
Apr 29, 2014
54
*/
Mar 3, 2020
Mar 3, 2020
55
public function __construct(array $values = [])
Apr 29, 2014
Apr 29, 2014
56
{
57
$this->factories = new \SplObjectStorage();
58
$this->protected = new \SplObjectStorage();
59
60
foreach ($values as $key => $value) {
61
$this->offsetSet($key, $value);
62
}
63
}
64
65
/**
66
* Sets a parameter or an object.
67
*
68
* Objects must be defined as Closures.
69
*
70
* Allowing any PHP callable leads to difficult to debug problems
71
* as function names (strings) are callable (creating a function with
72
* the same name as an existing parameter would break your container).
73
*
Aug 1, 2015
Aug 1, 2015
74
* @param string $id The unique identifier for the parameter or object
75
* @param mixed $value The value of the parameter or a closure to define an object
76
*
Oct 28, 2021
Oct 28, 2021
77
* @return void
78
*
Jul 7, 2017
Jul 7, 2017
79
* @throws FrozenServiceException Prevent override of a frozen service
Apr 29, 2014
Apr 29, 2014
80
*/
Oct 28, 2021
Oct 28, 2021
81
#[\ReturnTypeWillChange]
82
public function offsetSet($id, $value)
Apr 29, 2014
Apr 29, 2014
83
{
84
if (isset($this->frozen[$id])) {
Jul 3, 2017
Jul 3, 2017
85
throw new FrozenServiceException($id);
Apr 29, 2014
Apr 29, 2014
86
}
87
88
$this->values[$id] = $value;
89
$this->keys[$id] = true;
90
}
91
92
/**
93
* Gets a parameter or an object.
94
*
95
* @param string $id The unique identifier for the parameter or object
96
*
97
* @return mixed The value of the parameter or an object
98
*
Jul 7, 2017
Jul 7, 2017
99
* @throws UnknownIdentifierException If the identifier is not defined
Apr 29, 2014
Apr 29, 2014
100
*/
Oct 28, 2021
Oct 28, 2021
101
#[\ReturnTypeWillChange]
Apr 29, 2014
Apr 29, 2014
102
public function offsetGet($id)
103
{
104
if (!isset($this->keys[$id])) {
Jul 3, 2017
Jul 3, 2017
105
throw new UnknownIdentifierException($id);
Apr 29, 2014
Apr 29, 2014
106
}
107
108
if (
109
isset($this->raw[$id])
Jan 18, 2018
Jan 18, 2018
110
|| !\is_object($this->values[$id])
Apr 29, 2014
Apr 29, 2014
111
|| isset($this->protected[$this->values[$id]])
Jan 18, 2018
Jan 18, 2018
112
|| !\method_exists($this->values[$id], '__invoke')
Apr 29, 2014
Apr 29, 2014
113
) {
114
return $this->values[$id];
115
}
116
117
if (isset($this->factories[$this->values[$id]])) {
118
return $this->values[$id]($this);
119
}
120
Jul 12, 2014
Jul 12, 2014
121
$raw = $this->values[$id];
122
$val = $this->values[$id] = $raw($this);
123
$this->raw[$id] = $raw;
124
Apr 29, 2014
Apr 29, 2014
125
$this->frozen[$id] = true;
126
Jul 12, 2014
Jul 12, 2014
127
return $val;
Apr 29, 2014
Apr 29, 2014
128
}
129
130
/**
131
* Checks if a parameter or an object is set.
132
*
133
* @param string $id The unique identifier for the parameter or object
Oct 28, 2021
Oct 28, 2021
134
*
135
* @return bool
Apr 29, 2014
Apr 29, 2014
136
*/
Oct 28, 2021
Oct 28, 2021
137
#[\ReturnTypeWillChange]
138
public function offsetExists($id)
Apr 29, 2014
Apr 29, 2014
139
{
140
return isset($this->keys[$id]);
141
}
142
143
/**
144
* Unsets a parameter or an object.
145
*
146
* @param string $id The unique identifier for the parameter or object
Oct 28, 2021
Oct 28, 2021
147
*
148
* @return void
Apr 29, 2014
Apr 29, 2014
149
*/
Oct 28, 2021
Oct 28, 2021
150
#[\ReturnTypeWillChange]
151
public function offsetUnset($id)
Apr 29, 2014
Apr 29, 2014
152
{
153
if (isset($this->keys[$id])) {
Jan 18, 2018
Jan 18, 2018
154
if (\is_object($this->values[$id])) {
Apr 29, 2014
Apr 29, 2014
155
unset($this->factories[$this->values[$id]], $this->protected[$this->values[$id]]);
156
}
157
158
unset($this->values[$id], $this->frozen[$id], $this->raw[$id], $this->keys[$id]);
159
}
160
}
161
162
/**
163
* Marks a callable as being a factory service.
164
*
165
* @param callable $callable A service definition to be used as a factory
166
*
167
* @return callable The passed callable
168
*
Jul 7, 2017
Jul 7, 2017
169
* @throws ExpectedInvokableException Service definition has to be a closure or an invokable object
Apr 29, 2014
Apr 29, 2014
170
*/
171
public function factory($callable)
172
{
Nov 24, 2020
Nov 24, 2020
173
if (!\is_object($callable) || !\method_exists($callable, '__invoke')) {
Jul 3, 2017
Jul 3, 2017
174
throw new ExpectedInvokableException('Service definition is not a Closure or invokable object.');
Apr 29, 2014
Apr 29, 2014
175
}
176
Nov 12, 2025
Nov 12, 2025
177
$this->factories->offsetSet($callable);
Apr 29, 2014
Apr 29, 2014
178
179
return $callable;
180
}
181
182
/**
183
* Protects a callable from being interpreted as a service.
184
*
185
* This is useful when you want to store a callable as a parameter.
186
*
187
* @param callable $callable A callable to protect from being evaluated
188
*
189
* @return callable The passed callable
190
*
Jul 7, 2017
Jul 7, 2017
191
* @throws ExpectedInvokableException Service definition has to be a closure or an invokable object
Apr 29, 2014
Apr 29, 2014
192
*/
193
public function protect($callable)
194
{
Nov 24, 2020
Nov 24, 2020
195
if (!\is_object($callable) || !\method_exists($callable, '__invoke')) {
Jul 3, 2017
Jul 3, 2017
196
throw new ExpectedInvokableException('Callable is not a Closure or invokable object.');
Apr 29, 2014
Apr 29, 2014
197
}
198
Feb 25, 2026
Feb 25, 2026
199
$this->protected->offsetSet($callable);
Apr 29, 2014
Apr 29, 2014
200
201
return $callable;
202
}
203
204
/**
205
* Gets a parameter or the closure defining an object.
206
*
207
* @param string $id The unique identifier for the parameter or object
208
*
209
* @return mixed The value of the parameter or the closure defining an object
210
*
Jul 7, 2017
Jul 7, 2017
211
* @throws UnknownIdentifierException If the identifier is not defined
Apr 29, 2014
Apr 29, 2014
212
*/
213
public function raw($id)
214
{
215
if (!isset($this->keys[$id])) {
Jul 3, 2017
Jul 3, 2017
216
throw new UnknownIdentifierException($id);
Apr 29, 2014
Apr 29, 2014
217
}
218
219
if (isset($this->raw[$id])) {
220
return $this->raw[$id];
221
}
222
223
return $this->values[$id];
224
}
225
226
/**
227
* Extends an object definition.
228
*
229
* Useful when you want to extend an existing object definition,
230
* without necessarily loading that object.
231
*
232
* @param string $id The unique identifier for the object
233
* @param callable $callable A service definition to extend the original
234
*
235
* @return callable The wrapped callable
236
*
Jul 7, 2017
Jul 7, 2017
237
* @throws UnknownIdentifierException If the identifier is not defined
238
* @throws FrozenServiceException If the service is frozen
239
* @throws InvalidServiceIdentifierException If the identifier belongs to a parameter
240
* @throws ExpectedInvokableException If the extension callable is not a closure or an invokable object
Apr 29, 2014
Apr 29, 2014
241
*/
242
public function extend($id, $callable)
243
{
244
if (!isset($this->keys[$id])) {
Jul 3, 2017
Jul 3, 2017
245
throw new UnknownIdentifierException($id);
246
}
247
248
if (isset($this->frozen[$id])) {
249
throw new FrozenServiceException($id);
Apr 29, 2014
Apr 29, 2014
250
}
251
Jan 18, 2018
Jan 18, 2018
252
if (!\is_object($this->values[$id]) || !\method_exists($this->values[$id], '__invoke')) {
Jul 3, 2017
Jul 3, 2017
253
throw new InvalidServiceIdentifierException($id);
Apr 29, 2014
Apr 29, 2014
254
}
255
Jul 23, 2017
Jul 23, 2017
256
if (isset($this->protected[$this->values[$id]])) {
Mar 3, 2020
Mar 3, 2020
257
@\trigger_error(\sprintf('How Pimple behaves when extending protected closures will be fixed in Pimple 4. Are you sure "%s" should be protected?', $id), E_USER_DEPRECATED);
Jul 23, 2017
Jul 23, 2017
258
}
259
Jan 18, 2018
Jan 18, 2018
260
if (!\is_object($callable) || !\method_exists($callable, '__invoke')) {
Jul 3, 2017
Jul 3, 2017
261
throw new ExpectedInvokableException('Extension service definition is not a Closure or invokable object.');
Apr 29, 2014
Apr 29, 2014
262
}
263
264
$factory = $this->values[$id];
265
266
$extended = function ($c) use ($callable, $factory) {
267
return $callable($factory($c), $c);
268
};
269
270
if (isset($this->factories[$factory])) {
Feb 25, 2026
Feb 25, 2026
271
$this->factories->offsetUnset($factory);
272
$this->factories->offsetSet($extended);
Apr 29, 2014
Apr 29, 2014
273
}
274
275
return $this[$id] = $extended;
276
}
277
278
/**
279
* Returns all defined value names.
280
*
281
* @return array An array of value names
282
*/
283
public function keys()
284
{
Jan 18, 2018
Jan 18, 2018
285
return \array_keys($this->values);
Apr 29, 2014
Apr 29, 2014
286
}
287
288
/**
289
* Registers a service provider.
290
*
Oct 27, 2021
Oct 27, 2021
291
* @param array $values An array of values that customizes the provider
Apr 29, 2014
Apr 29, 2014
292
*
293
* @return static
294
*/
Mar 3, 2020
Mar 3, 2020
295
public function register(ServiceProviderInterface $provider, array $values = [])
Apr 29, 2014
Apr 29, 2014
296
{
297
$provider->register($this);
298
299
foreach ($values as $key => $value) {
300
$this[$key] = $value;
301
}
302
303
return $this;
304
}
305
}