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
Die folgenden Funktionen werden zusätzlich verwendet PhpErrorsAsExceptions PhpCreateUserObject PhpVarDumpAsHtmlcomment
<?php /** * mpl by ERB software * @author stefan.erb(at)erb-software.com */ require_once(dirname(__FILE__).'/AbstractMultiExtends.php'); /** * ============================ * Beispiel * ============================ */ // Erste Parentklasse class Mutter{ protected $name = 'Vreni'; public function __construct(){} public function gibEssen(){return 'Apfel'; } static protected function sagHallo($name){return "Mutter sagt 'Hallo {$name}'";} private function tschuess(){} } // Zweite Parentklasse class Vater{ public $nachname; public function __construct($vorname, $nachname){$this->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', "<br />\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 */ ?>
<?php /** * mpl by ERB software * @author stefan.erb(at)erb-software.com */ //TODO Statische Aufrufe ebenfalls behandeln (__callStatic geht erst ab PHP 5.3) //TODO Beim Aufruf prüfen ob die Methode im Original Protected ist //TODO Bei doppelten Properties/Methodes bestimmen welcher Parent gilt require_once(dirname(__FILE__).'/packages/functions/exceptionErrorHandler.php'); require_once(dirname(__FILE__).'/packages/functions/createUserObject.php'); require_once(dirname(__FILE__).'/packages/functions/varDumpAsHtmlcomment.php'); /** * ============================ * Abstracte Klasse * ============================ */ abstract class AbstractMultiExtends{ private $methods = array(); private $properties = array(); private $objects = array(); const C_METHOD = 'methods'; const C_PROPERTY = 'properties'; /** * ein weitere ExtendesClasse hinzufügen * @param String $name * @param Array $params */ final protected function addExtendedClass($className, $params = array()){ //ReflectionClass erstellen $reflection = new ReflectionClass($className); //Eine Wrapperklasse erstellen, damit die Protected-Methodes Public werden $wrapperClassName = self::createWrapperClass($reflection); //Falls nur ein Parameter angegeben wird, diesen in einen Array schreiben if(!is_array($params)) $params = array($params); //Objecktname definieren $objectName = self::getObjectName($wrapperClassName); //Eine Instance der Wrapperklasse anlegen und in den privaten Array speichern $this->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<String> $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[] = <<<EOT class $wrapperName extends $className{ public function __construct(){ \$pStrings = \$params = func_get_args(); array_walk(\$pStrings, create_function('&\$item, \$key', '\$item = "\\\$params[\'{\$key}\']";')); eval('parent::__construct(' . implode(',', \$pStrings) . ');'); } EOT; //Die Methoden hinzufügen $this->createWrapperMethodes($lines, $reflection); //Properties hinzufügen $this->createWrapperProperies($lines, $reflection); //Klasse schliessen $lines[] = <<<EOT } EOT; //Aus allen Zeilen ein String erstellen $classPhp = implode("\n", $lines); var_dump_as_htmlcomment($classPhp); //Die Klasse laden eval($classPhp); return $wrapperName; } /** * Erstellen der Wrappermethoden für die Wrapperklasse * @param $lines * @param $reflection */ final private function createWrapperMethodes(&$lines, ReflectionClass &$reflection){ foreach($reflection->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[] = <<<EOT {$modifiers} function {$method->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[] = <<<EOT public function __get(\$name){ \$protectedProperties = array({$propertiesS}); if(in_array(\$name, \$protectedProperties)) return \$this->\$name; } EOT; } } ?>