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