Guest User

http://stackoverflow.com/questions/18114141/full-inheritance

a guest
Nov 20th, 2013
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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.         {
  74.             return call_user_func_array($this->{$Key}, $Params);
  75.         }
  76.         elseif(is_callable($base->{$Key}))
  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.    
  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.        
  162.         return $old;
  163.     }
  164.    
  165.     // Note Uses shared version of water and can cause notices
  166.     function PourWater()
  167.     {
  168.         printf('Adding Water: %d%s', $this['Water'], "\n");
  169.     }
  170. }
  171.  
  172. abstract class Decorator extends Component
  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.         $this->SetFunction('SuperChain', 'doSuperChain');
  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.         printf('Adding sugar: %d%s', 1, "\n");
  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.         $this->parent->doProduce();
  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');
Add Comment
Please, Sign In to add comment