2012-08-24 11 views
7

Gibt es eine Möglichkeit, die Konstanten einer Klasse dynamisch zu erstellen? Ich weiß, dass dies ein wenig seltsam klingt, aber lassen Sie mich erklären, was ich versuche zu tun:Dynamische Konstanten in PHP?

  • ich eine Enum-Klasse haben, wer Attribute definiert werden durch statische const Definitionen
  • Diese Klasse erweitert die PHP SplEnum Klasse
  • Anstatt Typ in jeder dieser Definitionen in Code würde Ich mag eine statische haben initialiser in die Datenbank zu gehen und ziehen die aufgezählten Werte

Vielleicht wie dies irgendwas:

class myEnum extends SplEnum { 
    public static function init() { 
     $myNameValuePair = DB_Functions::get_enum_list(); 
     foreach ($myNameValuePair as $name => $value) { 
      $const = array (self , $name); 
      $const = $value; 
     } 
    } 
} 

Ich weiß, dass dies nicht funktioniert, da es nicht CONST, sondern statische Variablen setzt. Vielleicht ist meine ganze Idee haarig und es gibt eine bessere Technik dafür. Wie auch immer, jede Methode, um das Endziel zu erreichen, wird sehr geschätzt.

UPDATE

ich denke, es könnte hilfreich sein, ein wenig mehr klar auf meine Ziele zu sein, weil ich ganz möglicherweise ist es denke, dass meine Verwendung von Konstanten nicht gut ist. Grundsätzlich möchte ich ist erreichen typisch für die Anforderungen der Aufzählungsliste:

  1. Constrain Funktionssignaturen. Ich möchte in der Lage sein, nach einem "Satz" von Werten als Eingabe für eine Funktion zu fragen. Zum Beispiel:

    public function do_something (ENUM_Types $ type) {}

  2. Einfach und Compact. Erlauben Sie eine einfache und kompakte Syntax, wenn Sie im Code verwendet werden. Zum Beispiel bei der Verwendung von Konstanten, ich könnte eine bedingte Anweisung so etwas wie schreiben:

    if ($ my_var === ENUM_Types :: TypeA) {}

  3. Dynamische Aufzählung. Ich möchte, dass diese Aufzählung über das Frontend verwaltet und in der Datenbank gespeichert wird (ich benutze dafür die wordpress Admin-Bildschirme). Zur Laufzeit sollte diese "Liste" aus der DB herausgezogen und dem Code als Enumeration (oder ähnliche Struktur, die die oben genannten Ziele erreicht) zur Verfügung gestellt werden.

+6

Per Definition ist eine Konstante nicht dynamisch sein kann. Warum nicht einfach statische Variablen verwenden? – Matt

+0

Nun, ja, ich weiß und deshalb habe ich gesagt, es könnte ein bisschen seltsam erscheinen. Ich werde die Frage ein wenig auf den neuesten Stand bringen, um klarer zu machen, was ich erreichen möchte. – ken

+0

Mit anderen Worten: Sie möchten keine dynamischen Konstanten, sondern dynamische Enums. – EthanB

Antwort

8

Wickeln Sie Ihre "Enum" Werte in einer Singleton und Umsetzung der (nicht statisch) Magie __get Methode:

<?php 
class DynamicEnums { 

    private static $singleton; 

    private $enum_values; 

    public static function singleton() { 
    if (!self::$singleton) { 
     self::$singleton = new DynamicEnums(); 
    } 
    return self::$singleton; 
    } 

    function __construct() { 
    $this->enum_values = array(//fetch from somewhere 
     'one' => 'two', 
     'buckle' => 'my shoe!', 
    ); 
    } 

    function __get($name) { 
    return $this->enum_values[$name]; //or throw Exception? 
    } 

    public static function values() { 
    return self::singleton()->enum_values; //warning... mutable! 
    } 
} 

für Bonuspunkte, erstellen Sie eine (nicht-OO) Funktion, die die Singleton zurückgibt:

function DynamicEnums() { 
    return DynamicEnums::singleton(); 
} 

Verbraucher von "DynamicEnums" würde wie folgt aussehen:

echo DynamicEnums::singleton()->one; 
echo DynamicEnums()->one;   //can you feel the magic? 
print_r(DynamicEnums::values()); 

[bearbeiten ] Enum-like.

+0

Faule Bewertung, nicht wahr? –

+1

+1 für Magie ... –

+0

Das sieht gut aus. Ich glaube, dass es alle meine Anforderungen erfüllt. Vielen Dank für die Magie. : ^) – ken

0

Sie könnten etwas wie Const = $$ Konstante tun. Dann könnten Sie $ contant = was auch immer setzen. ODER Sie könnten eine geschützte Eigenschaft verwenden, da sie dynamisch sein soll und Konstanten nicht. Beispiel:

class Foo { 

protected $test = ''; 

function set($bar){ 
    $this->test = $bar; 
} 
function get($bar){ 
    return $this->test; 
} 


} 

$foobar = new Foo(); 
$foobar->set('test'); 
echo $foobar->get('test'); 
+0

Per Definition kann eine Konstante nicht dynamisch sein. Es * muss * auf einen Literalwert gesetzt werden. – Matt

+0

Wie wäre es mit einer Eigenschaft, die geschützt ist und wie eine Psuedo-Konstante verwendet? –

+0

Können Sie beschreiben, was Sie in Ihrer Antwort meinen? – Matt

0

Ich empfehle es nicht, aber eval() ... bitte nicht.

Ich habe Autoloader modifiziert, um automatisch Fehlertypen zu definieren, die fehlen oder falsch geschrieben sind. Grund: Sie können eine nicht abgefangene Ausnahme abfangen, aber Sie können nicht von PHP_FATAL wiederherstellen, wenn Sie einen Tippfehler in Ihrer Ausnahmeklasse instanziieren.

7

F: Gibt es eine Möglichkeit, die Konstanten einer Klasse dynamisch zu erstellen?

Die Antwort ist 'Ja', aber nicht das tun :)

class EnumFactory { 

    public static function create($class, array $constants) { 
     $declaration = ''; 
     foreach($constants as $name => $value) { 
      $declaration .= 'const ' . $name . ' = ' . $value . ';'; 
     } 
     eval("class $class { $declaration }"); 
    } 

} 

EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2)); 
echo darkSide::FOO . ' ' . darkSide::BAR; 

Nächste Frage ...

Q: Constrain Funktionssignaturen. Ich möchte in der Lage sein, nach einem "Satz" von Werten als Eingabe für eine Funktion zu fragen. Zum Beispiel: public function do_something (ENUM_Types $type) {}

Nach den manual, in diesem Fall $type ist, muss eine Instanz der ENUM_Types Klasse sein. Aber für Konstante ist es unmöglich (sie können keine Objekte enthalten).

Aber warten ... Wir solchen Trick verwenden:

class Enum { 

    protected static $_constantToClassMap = array(); 
    protected static function who() { return __CLASS__; } 

    public static function registerConstants($constants) { 
     $class = static::who(); 
     foreach ($constants as $name => $value) { 
      self::$_constantToClassMap[$class . '_' . $name] = new $class(); 
     } 
    } 

    public static function __callStatic($name, $arguments) { 
     return self::$_constantToClassMap[static::who() . '_' . $name]; 
    } 

} 

class EnumFactory { 

    public static function create($class, $constants) { 
     $declaration = ''; 
     foreach($constants as $name => $value) { 
      $declaration .= 'const ' . $name . ' = ' . $value . ';'; 
     } 

     eval("class $class extends Enum { $declaration protected static function who() { return __CLASS__; } }"); 
     $class::registerConstants($constants); 
    } 

} 

EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2)); 
EnumFactory::create('aaa', array('FOO' => 1, 'BAR' => 2)); 

echo (aaa::BAR() instanceof aaa) ? 'Yes' : 'No'; // Yes 
echo (aaa::BAR() instanceof darkSide) ? 'Yes' : 'No'; // No 

Und danach können wir ein "Type Hinting" verwenden:

function doSomething(darkSide $var) { 
    echo 'Bu!'; 
} 

doSomething(darkSide::BAR()); 
doSomething(aaa::BAR()); 

Q: Einfache und Kompakt. Erlauben Sie eine einfache und kompakte Syntax, wenn Sie im Code verwendet werden. Zum Beispiel bei der Verwendung von Konstanten könnte ich eine bedingte Anweisung so etwas wie schreiben: if ($my_var === ENUM_Types::TypeA) {}

Sie Werte Ihrer pseudo-Konstanten in einer solchen Form verwenden:

if (darkSide::FOO === 1) {} 

F: Dynamische Aufzählung Ich möchte, dass diese Aufzählung über das Frontend verwaltet und in der Datenbank gespeichert wird (ich benutze dafür die wordpress Admin-Bildschirme). Zur Laufzeit sollte diese "Liste" aus der DB herausgezogen und dem Code als Enumeration (oder ähnliche Struktur, die die oben genannten Ziele erreicht) zur Verfügung gestellt werden.

Sie können Ihre Aufzählung init von Array an den EnumFactory::create($class, $constants) vorbei:

EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2)); 
+3

vielen Dank. Schön zu sehen, wie man das erreichen kann, wenn man bereit ist, auf der dunklen Seite zu gehen (aka, die Bewertungsseite). – ken