Enums sind leider in PHP nicht wirklich implementiert. Mit dieser Abstrakten Klasse ist es relativ einfach um Enums zu erstellen und zu verwenden
Als erstes defineren wir einfach mal ein Enum mit jeweils einem Wert.
<?php //Einbinden der AbstractEnum und createEnum() include_once('Enum.php'); //Einfacher Enum von Hand definieren class Size extends Enum{ public static function S(){return new self('S');} public static function M(){return new self('M');} public static function L(){return new self('L');} public static function XL(){return new self('XL');} } //Ein Wert aussuchen $m = Size::M(); $xl = Size::XL(); //Prüfen ob es sich um ein XL handelt //Variable gegen den Enum echo ($xl->equal(Size::XL())) ? 'Du bist dick<br />': 'na schön<br />'; //und den Enum gegen die Variable echo (Size::XL()->equal($m)) ? 'Du bist dick<br />': 'na schön<br />'; ?>
Ausgabe:
Du bist dick na schön
//Ein Einfacher Enum über einen Array erstellen. Array(name=>Value) createEnum('Sex', array('men' => 'm', 'women' => 'w')); echo Sex::men()->value; //m //Einfache Enums, bei denen die Namen und Values identisch sind, können noch einfacher erstellt werden createEnum('Lang', 'de', 'en'); echo Lang::de()->value; //de Enum::create('Color', 'red', 'blue', 'green'); echo Color::red()->value; //red
//Ausgabe des Wertes echo $m->value; //Ein Enum anhand des Wertes ermitteln $s = Size::getEnum('S'); //Ein Enum anhand des Keys ermitteln $l = Size::getEnumKey('L');
//Ein Wert aussuchen $m = Size::M(); //Einer Funktion den Enum als Parameter mitgeben function checkStock(Size $isize){ //TODO: Bestand mittels DB abfragen. Hier als Beispiel ist es Hardcodiert switch ($isize){ case Size::S(): return 3; case Size::M(): return 10; case Size::L(): return 0; } } //Funktion aufrufen echo checkStock($m); //10
//Ein Enum mit weiteren Parametern class Size extends Enum{ //Zuerst die Parameter defineren. In dem Fall die Grössenbez. für Europa un Amerika protected $paramNames = array('eu', 'us'); //Dann die einzelnen Werte defineren public static function S(){return new self('S', 44, 34);} public static function M(){return new self('M', 48, 38);} public static function L(){return new self('L', 54, 44);} public static function XL(){return new self('XL', 56, 46);} } //Ein Wert aussuchen $m = Size::M(); //Und auf die verschiedenen Werte zugreiffen echo "{$m->value} ist in EU-Grösse {$m->eu} und in US {$m->us}";
Ausgabe:
M ist in EU-Grösse 48 und in US 38
class Size extends Enum{ //Zuerst die Parameter defineren. In dem Fall die Grössenbez. für Europa un Amerika protected $paramNames = array('eu', 'us'); //Dann die einzelnen Werte defineren public static function S(){return new self('S', 44, 34);} public static function M(){return new self('M', 48, 38);} public static function L(){return new self('L', 54, 44);} public static function XL(){return new self('XL', 56, 46);} } //Die Size ableiten. Einige Werte überschreiben, einige Hinzufügen. //Die Parameter eu und us müssen nicht mehr neu definiert werden class ShortSize extends Size{ public static function S(){return new self('S', 46, 36);} public static function M(){return new self('M', 50, 40);} public static function XXL(){return new self('XXL', 62, 52);} } echo ShortSize::S()->eu; //46 echo ShortSize::L()->eu; //54 echo ShortSize::XXL()->eu; //62
function exceptionErrorHandler($errno, $errstr, $errfile, $errline ) { if($errno & ini_get('error_reporting')) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } } set_error_handler("exceptionErrorHandler"); try{ Enum::create('Sex', array('men' => 'm', 'women' => 'w')); $chield = Sex::getEnumKey('chield'); } catch(Exception $e){ echo "<b>".$e->getMessage()."</b><br />\n"; echo nl2br($e->getTraceAsString()); }
no Enum found for 'chield' in 'Sex' #0 C:\xampp\htdocs\lib\enum\Enum.php(142): Enum->__getEnumKey('chield', 'Sex') #1 C:\xampp\htdocs\test\test3.php(20): Enum::getEnumKey('chield') #2 {main}
<?php /** * mpl by ERB software * @author stefan.erb(at)erb-software.com * @since PHP 5.2 */ interface IEnum{ /** * S T A T I S C H E M E T H O D E N */ /** * analog der Funktion createEnum($name, $enums) * @param String Name des Enums * @param Array oder Werteliste (siehe Beispiele) * @static */ public static function create($name, $enums); /** * erstellt eine leere Instance der Enumklasse. Dies wird verwednet um auf * Funktionen wie getEnum() etc zuzugreiffen ohne einen bestimmten ENUM auszuwählen * @return Enum * @static */ public static function getInstance(); /** * Erstellt ein Enum anhand des Wertes * @param Wert * @return Enum * @static */ public static function getEnum($value); /** * Erstellt ein Enum anhand des Keys * @param $key * @return Enum * @static */ public static function getEnumKey($key); /** * wandelt die Enums in einen Array array('EnumName' => EnumValue) * @return array * @static */ public static function toArray($paramName = 'value'); /** * gibt alle Values als Array aus * @param $glue * @return String * @static */ public static function implode($glue, $paramName = 'value'); /** * O B J E K T - M E T H O D E N */ /** * constructer * @param $value * @param $paramlist */ public function __construct($value = NULL); /** * gibt den Enum als String zurück. Dies entspricht dem Value * @return String */ public function __toString(); /** * überprüft ob der Enum dem ausgewählten Enum entspricht * @param $var * @return Boolean */ public function equal($var); /** * gibt ein Enum anhand eines passenden Wertes zurück * @param $value * @param $className * @return Enum */ public function __getEnum($value, $className); } ?>
<?php /** * mpl by ERB software * @author stefan.erb(at)erb-software.com * @since PHP 5.2 (Für PHP 5.3 kann man einige Dinge einfacher machen) */ /** * Die Klasse Enum ist ein Kunstrukt zum Erstellen von Enumeratoren */ /** * php52.php beinhaltet die Funktion get_called_class() für PHP52 * Ab PHP53 wirden diese Datei die die Funktion für PHP52 zur Verfügung stellt * nicht mehr gebraucht. */ require_once(dirname(__FILE__).'/php52.php'); require_once(dirname(__FILE__).'/IEnum.php'); /** * Die Funktion createEnum erstellt eine Enumklasse * @param String Name des Enums * @param Array oder Werteliste (siehe Beispiele) * @example * // Enum erstellen mit einer beliebigen Anzahl Parameter * createEnum('Enum1', 'a', 'b'); * echo Enum1::a(); //-> a * * // Enum erstellen mit einem Array. Der Key ist der Name der Funktion * createEnum('Enum2', array('A' => 'aa', 'B' => 'bb')); * echo Enum2::B(); //-> bb * * // Enum erstellen mit einem Array. Der Funktionsname ist gleich dem value * createEnum('Enum3', array('aaa', 'bbb')); * echo Enum3::aaa(); //-> aaa */ function createEnum($name, $enums){ $params = func_get_args(); return call_user_func_array(array('Enum', 'create'), $params); } /* * @example * class Enum1 extends AbstractEnum{ * // die ersten 3 Funktionen müssen so 1:1 übernommen werden * protected static function className(){return __CLASS__;} * public static function getInstance(){return new self();} * public static function getEnum($value){$e = new self(); return $e->createEnum($value);} * // Ab hier kommen die verschiedenen Enums * public static function A(){return new self('a');} * public static function B(){return new self('b');} * } * * $enum = Enum1::A(); * switch ($enum){ * case Enum1::A(): echo 'a'; break; * case Enum1::B(): echo 'b'; break; * default: echo 'default'; * } * if (Enum1::A()->equal($enum)) echo 'HalloA1'; * $enum = Enum1::getEnum('a'); */ class Enum implements IEnum{ static public $index; protected $paramNames = array(); /** * S T A T I S C H E M E T H O D E N */ /** * analog der Funktion createEnum($name, $enums) * @param String Name des Enums * @param Array oder Werteliste (siehe Beispiele) * @static * @example * // Enum erstellen mit einer beliebigen Anzahl Parameter * Enum::create('Enum1', 'a', 'b'); * echo Enum1::a(); //-> a * * // Enum erstellen mit einem Array. Der Key ist der Name der Funktion * Enum::create('Enum2', array('A' => 'aa', 'B' => 'bb')); * echo Enum2::B(); //-> bb * * // Enum erstellen mit einem Array. Der Funktionsname ist gleich dem Value * // zusätzlich als ist diese Klasse eine Ableitung von Enum2 * Enum::create('Enum3 extends Enum2', array('aaa', 'bbb')); * echo Enum3::aaa(); //-> aaa * echo Enum3::B(); //-> bb */ public static function create($name, $enums){ if(!is_array($enums)){ $enums = func_get_args(); $name = array_shift($enums); } // Falls kein extends mitgegeben wurde, die Enum-Klasse als Extends angeben if (!preg_match('/^[[:alnum:]_]+[ ]+extends[ ]+[[:alnum:]_]+$/', $name)){ $name = "{$name} extends ".__CLASS__; } // Classencode generieren $php = "class {$name}{\n"; foreach($enums as $key => $value){ if (is_numeric($key)) list($key, $value) = array($value, $value); preg_match_all('/[[:alnum:]_]+/i', $key, $keyElements); $key = implode('', $keyElements[0]); $php .= "public static function {$key}(){return new self('{$value}');}\n"; } $php .= "}\n"; eval($php); } /** * erstellt eine leere Instance der Enumklasse. Dies wird verwednet um auf * Funktionen wie getEnum() etc zuzugreiffen ohne einen bestimmten ENUM auszuwählen * @return Enum * @static */ public static function getInstance(){ $class = get_called_class(); return new $class(); } /** * Erstellt ein Enum anhand des Wertes * @param Wert * @return Enum * @static */ public static function getEnum($value){ return self::getInstance()->__getEnum($value, get_called_class()); } /** * Erstellt ein Enum anhand des Keys * @param $key * @return Enum * @static */ public static function getEnumKey($key){ return self::getInstance()->__getEnumKey($key, get_called_class()); } /** * wandelt die Enums in einen Array array('EnumName' => EnumValue) * @return array * @static */ public static function toArray($paramName = 'value'){ return self::getInstance()->__toArray(get_called_class(), 'value'); } /** * gibt alle Values als Array aus * @param $glue * @return String * @static */ public static function implode($glue, $paramName = 'value'){ return implode($glue, self::toArray()); } /** * O B J E K T - M E T H O D E N */ /** * constructer * @param $value * @param $paramlist */ public function __construct($value = NULL){ $this->params = func_get_args(); $this->value = array_shift($this->params); foreach($this->paramNames as $index => $name){ $this->$name = $this->params[$index]; } } /** * gibt den Enum als String zurück. Dies entspricht dem Value * @return String */ public function __toString(){ return (String) $this->value; } /** * überprüft ob der Enum dem ausgewählten Enum entspricht * @param $var * @return Boolean * @example * $enum = Enum1::A(); * if (Enum1::A()->equal($enum)) echo 'HalloA1'; */ public function equal($var){ return (Boolean) (is_a($var, get_called_class())) and ($var == $this); } /** * gibt ein Enum anhand eines passenden Wertes zurück * @example * $enum = Enum1::getInstance()->__getEnum('a'); * @param $value * @param $className * @return Enum */ public function __getEnum($value, $className){ if($func = array_search($value, $this->__toArray($className))) return $this->$func(); throw new Exception("no Enum found for '{$value}' in '{$className}'"); } /** * Erstellt ein Array mit allen Enums dieses Types * @example $array = Enum1::getInstance()->__toArray(); * @return array('EnumName' => 'value') */ protected function __toArray($className, $paramName = 'value'){ $enums = array_diff(get_class_methods($className), get_class_methods(__CLASS__)); $er = error_reporting(E_ERROR); foreach($enums as $func){ if($this->$func() instanceof self) $array[$func] = $this->$func()->$paramName; } error_reporting($er); return $array; } /** * gibt ein Enum anhand eines passenden Wertes zurück * @example * $enum = Enum1::getInstance()->__getEnum('a'); * @param $value * @access protected * @return Enum */ protected function __getEnumKey($key, $className){ if(array_key_exists($key, $this->__toArray($className))) return $this->$key(); throw new Exception("no Enum found for '{$key}' in '{$className}'"); } } ?>
Unter PHP 5.3 ist die Funktion get_called_class() nicht bekannt. Diese ist aber sehr wichtig für die Enum-Klasse. In der Datei php52.php wird diese Funktion auch für PHP5.2 zr Verfügung gestellt.
<?php /******************************** * Retro-support of get_called_class() * Tested and works in PHP 5.2.4 * http://www.sol1.com.au/ * http://www.php.net/manual/de/function.get-called-class.php#93799 ********************************/ if(!function_exists('get_called_class')) { function get_called_class($bt = false,$l = 1) { if (!$bt) $bt = debug_backtrace(); if (!isset($bt[$l])) throw new Exception("Cannot find called class -> stack level too deep."); if (!isset($bt[$l]['type'])) { throw new Exception ('type not set'); } else switch ($bt[$l]['type']) { case '::': $lines = file($bt[$l]['file']); $i = 0; $callerLine = ''; do { $i++; $callerLine = $lines[$bt[$l]['line']-$i] . $callerLine; } while (stripos($callerLine,$bt[$l]['function']) === false); preg_match('/([a-zA-Z0-9\_]+)::'.$bt[$l]['function'].'/', $callerLine, $matches); if (!isset($matches[1])) { // must be an edge case. throw new Exception ("Could not find caller class: originating method call is obscured."); } switch ($matches[1]) { case 'self': case 'parent': return get_called_class($bt,$l+1); default: return $matches[1]; } // won't get here. case '->': switch ($bt[$l]['function']) { case '__get': // edge case -> get class of calling object if (!is_object($bt[$l]['object'])) throw new Exception ("Edge case fail. __get called on non object."); return get_class($bt[$l]['object']); default: return $bt[$l]['class']; } default: throw new Exception ("Unknown backtrace method type"); } } } ?>