PHP - Idee bzgl. Klassen-Vererbung



  • Hallo,

    wie Ihr wahrscheinlich wisst, kann man in PHP 5 ja auch Vererbung mittels "extends" nutzen. Allerdings beschränkt sich das auf die Tatsache, dass man neue Klassen jeweils nur von einer Eltern-Klasse ableiten kann.

    Ich hab mir diesbezüglich mal Gedanken gemacht und ein Konzept überlegt, mit dem man theoretisch mehrere Eltern-Klassen implementieren kann. Allerdings bin ich mir in Sachen Performanz nicht ganz sicher, ob dieses Konzept in der Realität auch sinnvoll wäre.

    Das Ganze funktioniert wie folgt: Man hat zunächst eine Basis-Interface-Klasse (nicht zu verwechseln mit dem Keyword "interface", es handelt sich tatsächlich um eine echte Klasse):

    class BasisInterface
    {
      var $m_interface_methods=array();
      var $m_interfaces=array();
    
      public function implement($interface)
      {
        if(!class_exists($interface))
          return false;
    
        $methods=get_class_methods($interface);
    
        eval("\$this->m_interfaces[]=new ".$interface."();");
        $i=end($this->m_interfaces);
    
        foreach($methods as $m)
        {
          $this->m_interface_methods[$m]=&$i;
        }
      }
    
      public function __call($method, $args)
      {
        if(isset($this->m_interface_methods[$method]))
          return call_user_func_array(array(&$this->m_interface_methods[$method], $method), $args);
      }
    }
    

    Jetzt kann man irgendwelche weiteren Klassen definieren, die als Elternklassen fungieren sollen. Als Beispiel:

    class LoggingInterface
    {
       function log($str)
       {
          [...mach irgendwas...]
       }
    }
    
    class XYZInterface
    {
      function machWas()
      {
      }
    }
    

    Wenn ich jetzt eine neue Klasse erstellen möchte, die die Eigenschaften beider Klassen (also LoggingInterface und XYZInterface) erben soll, dann mache ich das so:

    class MeineKlasse extends BasisInterface // Leite die Klasse vom Basis Interface ab.
    {
        public function __construct()
        {
          // Und jetzt kommt der springende Punkt. Mittels implement() pflanze ich die Elterneigenschaften ein.
           BasisInterface::implement("LoggingInterface");
           BasisInterface::implement("XYZInterface");
        } 
    
    }
    

    Und fortan kann ich alle Methoden beider Klassen nutzen. Getestet habe ich's bereits und es funktioniert auch ganz gut. Jedenfalls kommt es dem gewohnten C++-Verhalten näher als ich es sonst von PHP kenne. Man könnte das Prinzip auch noch mittels __set und __get auf Variablen erweitern.

    Ich hoffe, Ihr könnt dem Quellcode oben folgen. Prinzipiell werden alle Aufrufe von Klassenmethoden in __call abgefangen und dementsprechend an die Eltern weitergeleitet.

    Was meint Ihr, ist das eine sinnvolle Vorgehensweise oder nur eine unnötige Performance-Bremse?



  • Hm.

    Wenn beide Elternklasse dieselbe Methode definiert haben, gehts kaputt (bwz. dann wird die Methode von der später implementierten Klasse aufgerufen).



  • Das ist nunmal das Problem bei Mehrfachvererbung. Ansonsten sieht das doch sehr gut aus, interessant, was man mit PHP so machen kann. 😉



  • Ja, das mit der Methodenkollision ist mir auch aufgefallen. Allerdings wird man da so wahrscheinlich keine akzeptable Lösung finden. Man könnte zwar mehrere Methoden mti dem selben Namen mittels einer etwas anderen Array-Struktur registrieren, aber das Aufrufen würde dann nur unnötig kompliziert werden.

    Ich habe aber nochmal getter und setter-Funktionen für Membervariablen der Elternklassen eingebaut. Das Ganze sieht nun so aus:

    class BasisInterface
    {
        var $m_interface_methods=array();
        var $m_interface_vars=array();
        var $m_interfaces=array();
    
        public function implement($interface)
        {
            if (!class_exists($interface))
                return false;
    
            $methods=get_class_methods($interface);
    
            $this->m_interfaces[]=new ReflectionClass($interface);
            $i=end($this->m_interfaces);
    
            foreach($methods as $m)
            {
                if ($m)
                    $this->m_interface_methods[$m]=&$i;
            }
    
            $vars=get_class_vars($interface);
    
            foreach($vars as $v=>$val)
            {
                $this->m_interface_vars[$v]=&$i;
            }
        }
    
        public function __call($method, $args)
        {
            if (isset($this->m_interface_methods[$method]))
                return call_user_func_array(array(&$this->m_interface_methods[$method], $method), $args);
        }
    
        public function __set($name, $value)
        {
            if (isset($this->m_interface_vars[$name]))
                $this->m_interface_vars[$name]->$name=$value; // Parent
            else
                $this->$name=$value; // Local
        }
    
        public function __get($name)
        {
            if (isset($this->m_interface_vars[$name]))
                return $this->m_interface_vars[$name]->$name;
            else
                return $this->$name;
        }
    }
    

    ~Was mich unheimlich stört, sind die evals. Hat jemand vielleicht eine Idee, wie man die loswerden könnte?~

    EDIT: Das mit den evals hat sich erledigt :p



  • mammamia;


Log in to reply