======[PHP] Multi Extends====== Es ist mehr eine Spielerei. Es geht dabei darum, dass man eine Klasse bilden kann, die aus mehr als einer Parent-Klasse abgeleitet ist. Mit Der unten Aufgeführten Klasse 'AbstractMultiExtends' lässt sich dies erstellen ---- {{image class="left" url="images/icons/48/gtk-go-back-rtl.png"}} =====Ausgangslage===== ---- {{image class="left" url="images/icons/48/application-x-php.png"}} =====Voraussetzungen===== Die folgenden Funktionen werden zusätzlich verwendet [[PhpErrorsAsExceptions]] [[PhpCreateUserObject]] [[PhpVarDumpAsHtmlcomment]] {{image class="left" url="images/icons/48/application-x-php.png"}} =====Code===== ====Kleines Testspiel==== name = $name; $this->nachname = $nachname;} static public function gibGeld($betrag){return "{$betrag} Franken"; } static protected function sagHallo($name){return "Vater sagt 'Hallo {$name}'";} } //Klasse Kind. Abgeleitet von Vater und Mutter //Die Ableitungen werden durch die Abstrakte Klasse AbstractMultiExtends durchgeführt //Die Parentklassen werden im Constructeur angehängt //Das simuliert das Verhalten von 'class Kind extends Mutter, Vater{' class Kind extends AbstractMultiExtends{ public function __construct(){ parent::addExtendedClass('Mutter', 48); parent::addExtendedClass('Vater', array('Thomas', 'Muster')); } public function mutterSagtHallo(){ //Die Funktion sagHallo() ist in beiden Parents definiert. Da Mutter aber zuerst als //Parent definiert wurde, hat sie vorrang return $this->sagHallo('Max Muster'); } public function getName(){ return "Max {$this->nachname}"; } } //Test define('BRNL', "
\n"); $ich = new Kind(); echo $ich->name.BRNL; echo $ich->gibEssen().BRNL; echo $ich->gibGeld(10).BRNL; echo $ich->getName().BRNL; echo $ich->mutterSagtHallo().BRNL; echo $ich->nachname; /* Ausgabe: Apfel 10 Franken Max Muster Mutter sagt 'Hallo Max Muster' Muster */ ?>
====AbstractMultiExtends==== objects[$objectName] = create_user_object_array($wrapperClassName, $params); //Methodennamen der Klasse in einen privaten Array speichern $this->addItems($objectName, self::C_METHOD, $reflection->getMethods()); //Propertiesnamen der Klasse in einen privaten Array speichern $this->addItems($objectName, self::C_PROPERTY, $reflection->getProperties()); } /** * Methoden oder Properties der Extended-Klasse in den Index einfügen * @param String $name Objektname * @param Constante $var Art der items * @param Array $array Liste der items */ final private function addItems($objectName, $list, $items){ //nur items nehmen, die nicht private sind $items = array_filter($items, create_function('$item', 'return (!$item->isPrivate());')); //items auf den Namen reduzieren array_walk($items, create_function('&$item', '$item = $item->name;')); //Array mit den itemnamen als Key und dem Objektnamen als Value transferieren $newVars = array_fill_keys($items, "\$this->objects['{$objectName}']"); //items der itemliste hinzufügen. //Bei Namensgleichheit mit bestehenden wird einer bestehende Zuordnung wird die //Bestehende beibehalten $this->$list = array_merge($newVars, $this->$list); } /** * Aufruf einer Methode. Der Aufruf wird an das entsprechende Parentobjekt weitergeleitet * @param String $name * @param Array $params * @return Variant */ public function __call($name, $params){ //Prüfen ob die Methode in der Liste der Methoden vorhanden ist if(array_key_exists($name, $this->methods)){ //dazugehöriges Elternobjekt auslesen $objectPhp = $this->methods[$name]; $object = eval("return {$objectPhp};"); //Methode im Elternobjekt ausführen return call_user_func_array(array($object, $name), $params); } } /** * Aufruf eines Property. Der Aufruf wird an das entsprechende Parentobjekt weitergeleitet * @param String $name * @return Variant */ public function __get($name){ //Prüfen ob das Property in der Liste der Properties vorhanden ist if(array_key_exists($name, $this->properties)){ //dazugehöriges Elternobjekt auslesen $obj = $this->properties[$name]; //Property auslesen return eval("return {$obj}->{$name};"); } } /** * @param String $className * @return String */ static final private function getObjectName($className){return "obj{$className}";} /** * @param String $className * @return String */ static final private function getWrapperName($className){return "{$className}Wrapper";} /** * Erstellen einer Wrapperlasse um die ParentClass * @param String $className * @return String Name der Wrapperklasse */ final private function createWrapperClass(&$reflection){ $className = $reflection->name; //ReflectionObject der Klasse zur weiteren Analyse anlegen $wrapperName = self::getWrapperName($className); $objName = self::getObjectName($wrapperName); //Die Klasse zusammenstellen $lines[] = <<createWrapperMethodes($lines, $reflection); //Properties hinzufügen $this->createWrapperProperies($lines, $reflection); //Klasse schliessen $lines[] = <<getMethods() as $method){ if($method->isProtected()){ $params = array(); $modifiers = $method->getModifiers() - ReflectionMethod::IS_PROTECTED + ReflectionMethod::IS_PUBLIC; $modifiers = implode(' ', Reflection::getModifierNames($modifiers)); foreach($method->getParameters() as $param){ $params[] = $param->getName(); } array_walk($params, create_function('&$item, $key', '$item = "\${$item}";')); $paramString = implode(', ', $params); $lines[] = <<name}({$paramString}){ return parent::{$method->name}({$paramString}); } EOT; } } } /** * Erstellen der der __get() im Warapper um auf die Potected/Public-Properties der Parentklasse zuzugreiffen * @param $lines * @param $reflection */ final private function createWrapperProperies(&$lines, ReflectionClass &$reflection){ $properties = array(); foreach($reflection->getProperties() as $property){ if(!$property->isPrivate() && !$property->isStatic()) { $properties[] = "'{$property->name}'"; } } $propertiesS = implode(', ', $properties); $lines[] = <<\$name; } EOT; } } ?> ---- {{image class="left" alt="ico" url="images/icons/48/xfce4-ui.png"}} =====Kategorien===== [[CatPhp]] | [[CatLibrary]]