Guest User

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

a guest
Nov 19th, 2013
65
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.         $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.         $this['Water']          -= 20;
  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');
Add Comment
Please, Sign In to add comment