===== [PHP] Enum =====
Enums sind leider in PHP nicht wirklich implementiert. Mit dieser Abstrakten Klasse ist es relativ einfach
um Enums zu erstellen und zu verwenden
=====Beispiele=====
====Einfache Anwendung====
Als erstes defineren wir einfach mal ein Enum mit jeweils einem Wert.
equal(Size::XL())) ? 'Du bist dick
': 'na schön
';
//und den Enum gegen die Variable
echo (Size::XL()->equal($m)) ? 'Du bist dick
': 'na schön
';
?>
Ausgabe:
Du bist dick
na schön
====Weitere Varianten einen einfachen Enum zu erstellen====
//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
====Verschiedene Zugriffe====
//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');
====Der Enum als Funktionsparameter====
//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
====Enum mit mehreren Paramtern====
//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
====Ableiten von Enums====
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
====Zugriff auf ein Enum dens nicht gibt====
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 "".$e->getMessage()."
\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}
=====Code=====
====Interface IEnum.php====
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);
}
?>
====Klasse Enum====
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}'");
}
}
?>
====PHP52 Funktionen====
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.
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");
}
}
}
?>
----
{{image class="left" alt="ico" url="images/icons/48/zip.png"}}
{{tag>PHP}}