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