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'); |