View difference between Paste ID: NccJtwEU and 28KyKViy
SHOW: | | - or go back to the newest paste.
1
<?php
2
3
abstract class Component extends stdCLass implements ArrayAccess, Countable
4
{
5
	protected $Decorators	= array();
6
	protected $Water		= 0;
7
	protected $SharedProps  = 0;
8
	
9
	public function GetProperties(Component $Child)
10
	{
11
		foreach($this as $k => $v)
12
		{
13
			$Child->{$k} = &$this->{$k};
14
		}
15
		
16
		if(!isset($this->datahash))
17
		{
18
			$Child->base 	 = &$this;
19
			$Child->datahash = spl_object_hash($this);
20
		}
21
	}
22
	
23
	public function AddDecorator($func, $args = array())
24
	{
25
		if(is_callable($func))
26
		{
27
			array_push($this->Decorators, array($func, $args));
28
		}
29
		else
30
		{
31
			throw new InvalidArgumentException(sprintf('%s::AddDecorator(callable $func, array $args): Invalid function ( %s ).', get_class($this), var_export($func, true)));
32
		}
33
	}
34
	
35
	public function RemoveDecorator($func, $args = array())
36
	{
37
		foreach($this->Decorators as & $decorator)
38
		{
39
			if($decorator === array($func, $args))
40
			{
41
				unset($decorator);
42
				return true;
43
			}
44
		}
45
		
46
		return false;
47
	}
48
	
49
	public function Decorate()
50
	{
51
		foreach($this->Decorators as $call)
52
		{
53
			call_user_func_array($call[0], $call[1]);
54
		}
55
	}
56
	
57
	public function __call($Key, $Params)
58
	{
59
		$Key  = (string)$Key;
60
		$base = isset($this->base)
61
			? $this->base
62
			: $this
63
		;
64
		
65
		if(!isset($this->{$Key}) && !isset($base->{$Key}))
66
		{
67
			throw new BadMethodCallException(sprintf('Call to undefined method `%s::%s()`', get_class($this), $Key));
68
			return;
69
		}
70
		
71
		if(is_callable($this->{$Key}))
72
		{
73
			call_user_func_array($this->{$Key}, $Params);
74
		}
75
		elseif(is_callable($base->{$Key}))
76
		{
77
			call_user_func_array($base->{$Key}, $Params);
78
		}
79
		else
80
		{
81
			throw new BadMethodCallException(sprintf('Call to undefined method `%s::{%s}()`.', get_class($this), var_export($this->{$Key}, true)));
82
			return;
83
		}
84
		
85
	}
86
	
87
	private function getHash()
88
	{
89
		return isset($this->datahash)
90
			? $this->datahash
91
			: $this->datahash = spl_object_hash($this)
92
		;
93
	}
94
	
95
	public function offsetSet($offset, $value)
96
	{
97
		static $count = 0;
98
		
99
		$hash = $this->getHash();
100
		
101
		if (is_null($offset))
102
		{
103
			$this->{$hash.$count++} = $value;
104
			$this->SharedProps++;
105
		}
106
		else
107
		{
108
			if(!isset($this[$offset])) $this->SharedProps++;
109
			
110
			$this->{$hash.$offset} = $value;
111
		}
112
	}
113
	
114
	public function offsetExists($offset)
115
	{
116
		return isset($this->{$this->getHash().$offset});
117
	}
118
	
119
	public function offsetUnset($offset)
120
	{
121
		$hash = $this->getHash();
122
		
123
		if(isset($this->{$hash.$offset})) $this->SharedProps--;
124
		
125
		unset($this->{$hash.$offset});
126
	}
127
	
128
	public function &offsetGet($offset)
129
	{
130
		return $this->{$this->getHash().$offset};
131
	}
132
	
133
	public function count()
134
	{
135
		return count($this->SharedProps);
136
	}
137
	
138
	function SetFunction($name, $func)
139
	{
140
		$base = isset($this->base)
141
			? $this->base
142
			: $this
143
		;
144
		
145
		$old = isset($base->{$name})
146
			? $base->{$name}
147
			: NULL
148
		;
149
		
150
		if(!is_callable(array($this, $func)))
151
		{
152
			throw new InvalidArgumentException(sprintf('%s::SetFunction(): Undefined method `%s`', get_class($this), var_export($func, true)));
153
		}
154
		
155
		$this->{$name} = $base->{$name} = array($this, $func);
156
		
157
		return $old;
158
	}
159
	
160
	
161
	public function CallParent($Function)
162
	{
163
		$parent	= debug_backtrace();
164
		$parent	= get_parent_class($parent[1]['class']) or get_parent_class($this);
165
		$args	= func_get_args();
166
		
167
		if(method_exists($parent, $Function))
168
		{
169
			call_user_func_array($parent.'::'.$Function, $args);
170
		}
171
		else
172
		{
173
			call_user_func_array(array($this->parent, $Function), $args);
174
		}
175
	}
176
	
177
	// Note Uses shared version of water and can cause notices
178
	function PourWater()
179
	{
180
		printf('Adding Water: %d%s', $this['Water'], "\n");
181
	}
182
}
183
184
abstract class Decorator extends Component
185
{
186
	public function __construct(Component $Parent)
187
	{
188
		$this->parent = &$Parent;
189
		
190
		$Parent->GetProperties($this);
191
	}
192
}
193
194
class SimpleCofee extends Component
195
{
196
	protected $Name			= 'Cofee';
197
	protected $Cup 			= array();
198
	
199
	public function __construct($Parent = NULL)
200
	{
201
		$this->Water		 = 150;
202
		$this->Cup['cofeee'] = 25;
203
		
204
		if($Parent instanceof Component)
205
		{
206
			$Parent->GetProperties($this);
207
		}
208
		else
209
		{
210
			$this['Name']		= $this->Name;
211
			$this['Water']		= $this->Water;
212
			$this['Cup']		= $this->Cup;
213
		}
214
		
215
		$this->SetFunction('Produce', 'doProduce');
216
		$this->SetFunction('SuperChain', 'doSuperChain');
217
	}
218
	
219
	public function doProduce()
220
	{
221
		printf("Making %s....\n", $this->Name);
222
		
223
		$this->Decorate();
224
		
225
		//.....
226
		$this->PourWater();
227
		//......
228
		
229
		printf("Making %s: %s\n", $this['Name'], var_export($this['Cup'], true));		
230
	}
231
232
	public function doSuperChain()
233
	{
234
		print __CLASS__.'::SuperChain('.var_export(func_get_args(), true).")\n";
235
	}
236
}
237
238
class SimpleTea extends SimpleCofee
239
{
240
	protected $Name			= 'Tea';
241
	
242
	public function __construct($Parent = NULL)
243
	{
244
		$this->Water		 = 150;
245
		$this->Cup['tea']	 = 25;
246
		
247
		if($Parent instanceof Component)
248
		{
249
			$Parent->GetProperties($this);
250
		}
251
		else
252
		{
253
			$this['Name']		= $this->Name;
254
			$this['Water']		= $this->Water;
255
			$this['Cup']		= $this->Cup;
256
		}
257
258
		$this->SetFunction('Produce', 'doProduce');
259
		$this->SetFunction('SuperChain', 'doSuperChain');
260
	}
261
262
	public function doSuperChain()
263
	{
264
		print __CLASS__.'::SuperChain('.var_export(func_get_args(), true).")\n";
265
		
266
		self::CallParent('doSuperChain');
267
	}
268
}
269
270
271
class SugarCube extends Decorator
272
{
273
	public function __construct(Component $Parent)
274
	{
275
		parent::__construct($Parent);
276
		
277
		$Parent->AddDecorator(array($this, 'AddSugar'));
278
		
279
		$this->SetFunction('SuperChain', 'doSuperChain');
280
	}
281
	
282
	public function AddSugar()
283
	{
284
		$this['Cup']['Spoon']	 = 1;
285
		$this['Ammount']		 = @$this['Ammount'] + 1;
286
		$this['Water']			-= 10;
287
		
288
		printf('Adding sugar: %d%s', 1, "\n");
289
	}
290
291
	public function doSuperChain()
292
	{
293
		print __CLASS__.'::SuperChain('.var_export(func_get_args(), true).")\n";
294
		
295
		self::CallParent('doSuperChain');
296
	}
297
}
298
299
class DoubleSugarCube extends SugarCube
300
{
301
	protected $old;
302
303
	public function __construct(Component $Component)
304
	{
305
		parent::__construct($Component);
306
		
307
		$this->old = $this->SetFunction('Produce', 'doProduce');
308
		
309
		$this->SetFunction('SuperChain', 'doSuperChain');
310
	}
311
	
312
	public function AddSugar()
313
	{
314
		// Call parent class then parent object
315
		$this['Cup']['Spoon']	 = 1;
316
		$this['Ammount']	 	 = @$this['ammount'] + 2;
317-
}
317+
318
		
319
		printf('Adding sugar: %d%s', 2, "\n");
320
	}
321
	
322
	public function doProduce()
323
	{
324
		print "\nI have take over Produce!\n";
325
		print "But I'm a nice guy so I'll call my parent\n\n";
326
		
327
		// Call parent objects function
328
		$this->parent->doProduce();
329
	}
330
	
331
	public function doSuperChain()
332
	{
333
		print __CLASS__.'::SuperChain('.var_export(func_get_args(), true).")\n";
334
		
335
		self::CallParent('doSuperChain');
336
	}
337
}
338
339
340
$Sugar = 1;
341
$DoubleSugar = 1;
342
343
$Cofee = new SimpleCofee();
344
$Tea   = new SimpleTea();
345
346
$Cofee->Produce();
347
$Tea->Produce();
348
349
print "\n============\n\n";
350
351
if($Sugar)
352
{
353
	new SugarCube($Cofee);
354
	$Cofee->Produce();
355
	new SugarCube($Cofee);
356
	$Cofee->Produce();
357
}
358
359
if($DoubleSugar)
360
{
361
	new DoubleSugarCube($Tea);
362
	$Tea->Produce();
363
	new DoubleSugarCube($Tea);
364
	$Tea->Produce();
365
}
366
367
$Tea->SuperChain('test');