View difference between Paste ID: PUfFshcY and PLzsFRLk
SHOW: | | - or go back to the newest paste.
1-
class Container implements ContainerInterface {
1+
class Container implements ArrayAccess {
2
3
	/**
4
	 * Container bindings
5
	 * @var array
6
	 */
7
	protected $bindings = array();
8
9
	/**
10
	 * Container instances
11
	 * @var array
12
	 */
13
	protected $instances = array();
14
15
	/**
16
	 * Container Closures
17
	 * @var array
18
	 */
19
	protected $closures = array();
20
21
	/**
22
	 * Maximum depth of function makeClassWithParameters
23
	 * @var int
24
	 */
25
	protected $maxdepth = 10;
26
27
	// ================================================== //
28
29
	/**
30
	 * Public function to create new binding.
31
	 *
32
	 * @param string $key Binding name
33
	 * @param mixed $value Object to store
34
	 * @param bool $singleton Store as singleton?
35
	 * @return void
36
	 */
37
	public function bind($key, $value, $singleton = false)
38
	{
39
		$this->clearBind($key);
40
41
		$this->makeBind($key, $value, (bool)$singleton);
42
	}
43
44
	/**
45
	 * Function to get stored object or create new to store.
46
	 * If there's no stored object it will create new instance of
47
	 * class which name is $key
48
	 *
49
	 * @param string $key Binding name or class name
50
	 * @param array $parameters Parameters for new class
51
	 * @param bool $singleton Store new class as singleton?
52
	 * @return mixed
53
	 */
54
	public function make($key, $parameters = array(), $singleton = false)
55
	{
56
		if($bind = $this->getBind($key))
57
		{
58
			if(isset($bind['type']) and $bind['type'] == 'closure')
59
			{
60
				$instance = $this->closures[$key];
61
				$instance = $instance();
62
63
				if(isset($bind['singleton']) and $bind['singleton'] == true)
64
				{
65
					$this->clearBind($key);
66
67
					$this->makeBind($key, $instance, true);
68
				}
69
70
				return $instance;
71
			}
72
			elseif(isset($bind['type']) and $bind['type'] == 'instance')
73
			{
74
				return $this->instances[$key];
75
			}
76
77
			$this->clearBind($key);
78
			return false;
79
		}
80
		else
81
		{
82
			$instance = $this->makeClassWithParameters($key, (array)$parameters);
83
84
			if($instance != false)
85
			{
86
				$this->bind($key, $instance);
87
			}
88
89
			return $instance;
90
		}
91
	}
92
93
	// ================================================== //
94
95
	/**
96
	 * Creating new class with parameters.
97
	 * If new class constructor require another class as parameter
98
	 * it will be created, but max depth is limited!
99
	 *
100
	 * @throws OutOfBoundsException
101
	 * @uses ReflectionClass
102
	 *
103
	 * @param string $name Class name
104
	 * @param array $params Class parameters
105
	 * @param int $depth Depth counter
106
	 * @return mixed
107
	 */
108
	protected function makeClassWithParameters($name, array $params, $depth = 1)
109
	{
110
		if($depth >= $this->maxdepth)
111
		{
112
			throw new OutOfBoundsException('Maximum depth of makeClassWithParameters is '.$this->maxdepth);
113
			return false;
114
		}
115
116
		if(class_exists($name))
117
		{
118
			$class = new ReflectionClass($name);
119
120
			$constructor = $class->getConstructor();
121
122
			if(!is_null($constructor) and empty($params))
123
			{
124
				foreach($constructor->getParameters() as $paramdata)
125
				{
126
					$classparam = $paramdata->getClass();
127
128
					if(is_null($classparam))
129
					{
130
						if($paramdata->isOptional())
131
						{
132
							$params[] = $paramdata->getDefaultValue();
133
						}
134
						else
135
						{
136
							$params[] = null;
137
						}
138
					}
139
					else
140
					{
141
						$params[] = $this->makeClassWithParameters($classparam->name, array(), $depth+1);
142
					}
143
				}
144
			}
145
			
146
			return $class->newInstanceArgs($params);
147
		}
148
		else
149
		{
150
			return false;
151
		}
152
	}
153
154
	/**
155
	 * Getting bind if exist
156
	 *
157
	 * @return mixed
158
	 */
159
	protected function getBind($key)
160
	{
161
		return isset($this->bindings[$key]) ? $this->bindings[$key] : false;
162
	}
163
164
	/**
165
	 * Protected function to create new binding.
166
	 *
167
	 * @param string $key Binding name
168
	 * @param mixed $value Object to store
169
	 * @param bool $singleton Store as singleton?
170
	 * @return void
171
	 */
172
	protected function makeBind($key, $value, $singleton)
173
	{
174
		$bind = array();
175
176
		if($value instanceof Closure)
177
		{
178
			$bind['type'] = 'closure';
179
			$bind['singleton'] = (bool)$singleton;
180
			$this->closures[$key] = $value;
181
		}
182
		else
183
		{
184
			$bind['type'] = 'instance';
185
			$this->instances[$key] = $value;
186
		}
187
188
		$this->bindings[$key] = $bind;
189
	}
190
191
	/**
192
	 * Clear existing binding
193
	 *
194
	 * @param string $key Binding name
195
	 * @return void
196
	 */
197
	protected function clearBind($key)
198
	{
199
		unset($this->bindings[$key], $this->instances[$key], $this->closures[$key]);
200
	}
201
202
	// ================================================== //
203
204
	/**
205
	 * Getting container content as array
206
	 *
207
	 * @param string $key Binding name
208
	 * @return mixed
209
	 */
210
	public function offsetGet($key)
211
	{
212
		return $this->make($key);
213
	}
214
215
	/**
216
	 * Set container content as array
217
	 *
218
	 * @param string $key Binding name
219
	 * @param mixed $value Object to store
220
	 * @return void
221
	 */
222
	public function offsetSet($key, $value)
223
	{
224
		if(!($value instanceof Closure))
225
		{
226
			$value = function() use ($value) {
227
				return $value;
228
			};
229
		}
230
231
		$this->bind($key, $value, false);
232
	}
233
234
	/**
235
	 * Checking binding as container array
236
	 *
237
	 * @param string $key Binding name
238
	 * @return bool
239
	 */
240
	public function offsetExists($key)
241
	{
242
		return isset($this->bindings[$key]);
243
	}
244
245
	/**
246
	 * Using function unset for container as array
247
	 *
248
	 * @param string $key Binding name
249
	 * @return void
250
	 */
251
	public function offsetUnset($key)
252
	{
253
		$this->clearBind($key);
254
	}
255
256
	/**
257
	 * Magic method __get
258
	 *
259
	 * @param string $key
260
	 * @return mixed
261
	 */
262
	public function __get($key)
263
	{
264
		return $this[$key];
265
	}
266
267
	/**
268
	 * Magic method __set
269
	 *
270
	 * @param string $key
271
	 * @param mixed $value
272
	 * @return void
273
	 */
274
	public function __set($key, $value)
275
	{
276
		$this[$key] = $value;
277
	}
278
279
}